valor-software / ng2-file-upload

Easy to use Angular components for files upload
http://valor-software.github.io/ng2-file-upload/
MIT License
1.91k stars 662 forks source link

Unhandled Promise rejection: Template parse errors: Can't bind to 'uploader' since it isn't a known property of 'input'. (" #544

Closed pangky24 closed 7 years ago

pangky24 commented 7 years ago

I am using angular2 '2.4.0'. also I have downloaded ng2-file-upload/master version. but I meet the error below. what I try next..

error

`Unhandled Promise rejection: Template parse errors:
Can't bind to 'uploader' since it isn't a known property of 'input'. ("

</div> -->
<input type="file" ng2FileSelect [ERROR ->][uploader]="uploader" multiple  /><br/>
            {{tomorrow}}
            {{uploader}}
"): WatchfaceDetailComponent@111:33 ; Zone: <root> ; Task: Promise.then ; Value: SyntaxError {_nativeError: Error: Template parse errors:
Can't bind to 'uploader' since it isn't a known property of 'input'. (…} Error: Template parse errors:
Can't bind to 'uploader' since it isn't a known property of 'input'. ("

</div> -->
<input type="file" ng2FileSelect [ERROR ->][uploader]="uploader" multiple  /><br/>
            {{tomorrow}}
            {{uploader}}
"): WatchfaceDetailComponent@111:33
    at SyntaxError.BaseError [as constructor] (http://localhost:4200/vendor.bundle.js:75540:27)
    at new SyntaxError (http://localhost:4200/vendor.bundle.js:6679:16)
    at TemplateParser.parse (http://localhost:4200/vendor.bundle.js:20356:19)`

package.json

 `{
  "name": "watchmaster-service-admin",
  "version": "0.0.0",
  "license": "MIT",
  "angular-cli": {},
  "scripts": {
    "start": "ng serve --proxy-config proxy.conf.json",
    "lint": "tslint \"src/**/*.ts\"",
    "test": "ng test",
    "pree2e": "webdriver-manager update",
    "e2e": "protractor"
  },
  "private": true,
  "dependencies": {
    "@angular/common": "2.4.0",
    "@angular/compiler": "2.4.0",
    "@angular/core": "2.4.0",
    "@angular/forms": "2.4.0",
    "@angular/http": "2.4.0",
    "@angular/material": "^2.0.0-alpha.11-3",
    "@angular/platform-browser": "2.4.0",
    "@angular/platform-browser-dynamic": "2.4.0",
    "@angular/router": "3.2.3",
    "core-js": "^2.4.1",
    "hammerjs": "^2.0.8",
    "ng2-file-upload": "^1.0.3",
    "rxjs": "5.0.0-beta.12",
    "ts-helpers": "^1.1.1",
    "underscore": "^1.8.3",
    "systemjs": "^0.19.37",
    "zone.js": "^0.6.23",
    "angular2-moment": "^1.0.0-beta.5",
    "moment": "^2.15.1"
  },
  "devDependencies": {
    "@angular/compiler-cli": "2.4.0",
    "@types/hammerjs": "^2.0.33",
    "@types/jasmine": "2.5.38",
    "@types/node": "^6.0.42",
    "angular-cli": "1.0.0-beta.24",
    "codelyzer": "~2.0.0-beta.1",
    "jasmine-core": "2.5.2",
    "jasmine-spec-reporter": "2.5.0",
    "karma": "1.2.0",
    "karma-chrome-launcher": "^2.0.0",
    "karma-cli": "^1.0.1",
    "karma-jasmine": "^1.0.2",
    "karma-remap-istanbul": "^0.2.1",
    "protractor": "4.0.9",
    "ts-node": "1.2.1",
    "tslint": "^4.0.2",
    "typescript": "~2.0.3",
    "webdriver-manager": "10.2.5",
    "underscore": "^1.8.3"
  }
}
`

app.module.ts

 `import { CommonModule } from '@angular/common';

import { AppComponent } from './app.component';
import {routing, appRoutingProviders} from './app.routing';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { WatchfaceModule } from './watchface/watchface.module';
import { MenuModule } from './menu/menu.module';
import { ConfigModule } from './config/config.module';
import { PagerService } from './_services/index';
import {FileSelectDirective, FileDropDirective, FileUploader} from './ng2-file-upload';

/**
 * Bootstrap Modules - Start
 */
import { AlertModule } from './com/alert/alert.module';
import { AccordionModule } from './com/accordion/accordion.module';
import { ButtonsModule } from './com/buttons/buttons.module';
import { CarouselModule } from './com/carousel/carousel.module';
import { DropdownModule } from './com/dropdown/dropdown.module';
import { ModalModule } from './com/modal/modal.module';
import { ProgressbarModule } from './com/progressbar/progressbar.module';
import { RatingModule } from './com/rating/rating.module';
import { TabsModule } from './com/tabs/tabs.module';
import { TooltipModule } from './com/tooltip/tooltip.module';
import { TypeaheadModule } from './com/typeahead/typeahead.module';
import { CollapseModule } from './com/collapse/collapse.module';
import { PaginationModule } from './com/pagination/pagination.module';
import { DatepickerModule } from './com/datepicker/datepicker.module';
import { TimepickerModule } from './com/timepicker/timepicker.module';

/**
 * Other Modules - Start
 */
import { NgGridModule } from './com/grid/modules/NgGrid.module'; // grid system

@NgModule({
  declarations: [
      AppComponent,
      FileSelectDirective,
      FileDropDirective,
    DatepickerDemoComponent,
  ],
  imports: [
    DatepickerModule,
    BrowserModule,
    FormsModule,
    HttpModule,
    routing,
    MenuModule,
    ConfigModule,
    WatchfaceModule,
    ReactiveFormsModule,       
    AlertModule,
    AccordionModule,
    ButtonsModule,
    CarouselModule,
    CollapseModule,
    DropdownModule,
    ModalModule,
    ProgressbarModule,
    RatingModule,
    TabsModule,
    TooltipModule,
    TypeaheadModule,
    TimepickerModule,
    PaginationModule,
    NgGridModule,//grid
  ],
  providers: [
    appRoutingProviders,
    PagerService
  ],
  bootstrap: [AppComponent]
})

export class AppModule {}
`

watchface-detail.component.ts

 `import { ActivatedRoute } from '@angular/router';
import { Component, OnInit, Input, Directive  } from '@angular/core';
import { FormGroup, FormBuilder, FormArray, Validators } from '@angular/forms';
import { Headers, RequestOptions, URLSearchParams } from '@angular/http';
import {FileSelectDirective, FileDropDirective, FileUploader} from '../ng2-file-upload';

import { Watchface } from './watchface';
import { WatchfaceService} from './watchface.service';
import * as moment from 'moment';

let template = require('./watchface-detail.component.html');

const URL = 'https://evening-anchorage-3159.herokuapp.com/api/';

@Component({
    //moduleId: module.id,
    selector: 'watchface-form',
    template: template
    ,
    providers: [WatchfaceService]
})

export class WatchfaceDetailComponent implements OnInit {
    //################################
    // FileUploader
    //################################
    //@Input("uploader") uploader:FileUploader = new FileUploader({url: URL});
    public uploader: FileUploader = new FileUploader({url: URL});

    //################################
    // datepicker
    //################################
    public dt: Date = new Date();
    public minDate: Date = void 0;
    public events: Array<any>;
    public tomorrow: Date;
    public afterTomorrow: Date;
    public formats: Array<string> = ['DD-MM-YYYY', 'YYYY/MM/DD', 'DD.MM.YYYY', 'shortDate'];
    public format: string = this.formats[0];
    public dateOptions: any = {
        formatYear: 'YY',
        startingDay: 1
    };
    private opened: boolean = false;

    //################################
    // paging, form validation
    //################################
    private allItems: any[];
    form: FormGroup;
    watchface: Watchface;

    itemNo: number;
    errorMessage: string;

    formErrors = {
        artist: '',
        artistId: '',
        description: '',
        featuredBanner: '',
        fileUpdatedAt: '',
        functions: '',
        image1: '',
        image2: '',
        image3: '',
        image4: '',
        image5: '',
        likes: '',
        needUpdate: '',
        order: '',
        packageNameAndroid: '',
        preview_round: '',
        preview_square: '',
        price: '',
        product_type: '',
        projectName: '',
        search: '',
        tags: '',
        title: '',
        watchface: '',

    };

    validationMessages = {
        artist: {
            required: 'artist is required.',
            minlength: 'artist must be 1 characters.',
            maxlength: 'artist can\'t be longer than 255 characters.'
        },
        artistId: {
            required: 'artist_id is required.',
            minlength: 'artist_id must be 1 characters.',
            maxlength: 'artist_id can\'t be longer than 255 characters.'
        },
        description: {
            required: 'description is required.',
            minlength: 'description must be 1 characters.',
            maxlength: 'description can\'t be longer than 255 characters.'
        },
        featuredBanner: {
            required: 'featuredBanner is required.',
            minlength: 'featuredBanner must be 1 characters.',
            maxlength: 'featuredBanner can\'t be longer than 255 characters.'
        },
        fileUpdatedAt: {
            required: 'fileUpdatedAt is required.',
            minlength: 'fileUpdatedAt must be 1 characters.',
            maxlength: 'fileUpdatedAt can\'t be longer than 255 characters.'
        },
        functions: {
            required: 'functions is required.',
            minlength: 'functions must be 1 characters.',
            maxlength: 'functions can\'t be longer than 255 characters.'
        },
        image1: {
            required: 'image1 is required.',
            minlength: 'image1 must be 1 characters.',
            maxlength: 'image1 can\'t be longer than 255 characters.'
        },
        image2: {
            required: 'image1 is required.',
            minlength: 'image1 must be 1 characters.',
            maxlength: 'image1 can\'t be longer than 255 characters.'
        },
        image3: {
            required: 'image1 is required.',
            minlength: 'image1 must be 1 characters.',
            maxlength: 'image1 can\'t be longer than 255 characters.'
        },
        image4: {
            required: 'image1 is required.',
            minlength: 'image1 must be 1 characters.',
            maxlength: 'image1 can\'t be longer than 255 characters.'
        },
        image5: {
            required: 'image1 is required.',
            minlength: 'image1 must be 1 characters.',
            maxlength: 'image1 can\'t be longer than 255 characters.'
        },
        likes: {
            required: 'likes is required.',
            minlength: 'likes must be 1 characters.',
            maxlength: 'likes can\'t be longer than 255 characters.'
        },
        needUpdate: {
            required: 'needUpdate is required.',
            minlength: 'needUpdate must be 1 characters.',
            maxlength: 'needUpdate can\'t be longer than 255 characters.'
        },
        order: {
            required: 'order is required.',
            minlength: 'order must be 1 characters.',
            maxlength: 'order can\'t be longer than 255 characters.'
        },
        packageNameAndroid: {
            required: 'packageNameAndroid is required.',
            minlength: 'packageNameAndroid must be 1 characters.',
            maxlength: 'packageNameAndroid can\'t be longer than 255 characters.'
        },
        preview_round: {
            required: 'preview_round is required.',
            minlength: 'preview_round must be 1 characters.',
            maxlength: 'preview_round can\'t be longer than 255 characters.'
        },
        preview_square: {
            required: 'preview_square is required.',
            minlength: 'preview_square must be 1 characters.',
            maxlength: 'preview_square can\'t be longer than 255 characters.'
        },
        price: {
            required: 'price is required.',
            minlength: 'price must be 1 characters.',
            maxlength: 'price can\'t be longer than 255 characters.'
        },
        product_type: {
            required: 'product_type is required.',
            minlength: 'product_type must be 1 characters.',
            maxlength: 'product_type can\'t be longer than 255 characters.'
        },
        projectName: {
            required: 'projectName is required.',
            minlength: 'projectName must be 1 characters.',
            maxlength: 'projectName can\'t be longer than 255 characters.'
        },
        search: {
            required: 'search is required.',
            minlength: 'search must be 1 characters.',
            maxlength: 'search can\'t be longer than 255 characters.'
        },
        tags: {
            required: 'tags is required.',
            minlength: 'tags must be 1 characters.',
            maxlength: 'tags can\'t be longer than 255 characters.'
        },
        title: {
            required: 'title is required.',
            minlength: 'title must be 1 characters.',
            maxlength: 'title can\'t be longer than 255 characters.'
        },
        watchface: {
            required: 'watchface is required.',
            minlength: 'watchface must be 1 characters.',
            maxlength: 'watchface can\'t be longer than 255 characters.'
        }
    };

    constructor(private watchfaceService: WatchfaceService, private route: ActivatedRoute, private fb: FormBuilder) {
        this.route.params.subscribe(
            params => {
                this.itemNo = params['no'];
            }
        );

        //################################
        // datepicker
        //################################
        (this.tomorrow = new Date()).setDate(this.tomorrow.getDate() + 1);
        (this.afterTomorrow = new Date()).setDate(this.tomorrow.getDate() + 2);
        (this.minDate = new Date()).setDate(this.minDate.getDate() - 1000);
        this.events = [
            { date: this.tomorrow, status: 'full' },
            { date: this.afterTomorrow, status: 'partially' }
        ];
    }

    ngOnInit() {
        this.getWatchface();
        // build the data model for our form
        this.buildForm();
    }

    getWatchface() {
        let params: URLSearchParams = new URLSearchParams();
        params.set('no', this.itemNo + "");
        this.watchfaceService.getWatchfaceList(params)
            .subscribe(
            allItems => {
                if (allItems != null && allItems.length > 0) {
                    this.watchface = allItems[0];
                    console.log(this.watchface);
                }
                //this.buildForm();
                //this.allItems = allItems;
            },
            error => this.errorMessage = <any>error);
    }

    processForm() {
        let formData: FormData = new FormData();

        console.log('processing', this.form.value);

    }

    /**
     * build the initial form
     */
    buildForm() {
        // build our form
        this.form = this.fb.group({
            no: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            //no: ['', Validators.required, [Validators.minLength(1), Validators.maxLength(255)]],
            artist: ['', Validators.required, [Validators.minLength(1), Validators.maxLength(255)]],
            artistId: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            description: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            featuredBanner: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            fileUpdatedAt: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            functions: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            image1: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            image2: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            image3: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            image4: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            image5: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            likes: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            order: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            packageNameAndroid: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            preview_round: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            preview_square: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            price: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            product_type: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            projectName: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            search: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            tags: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            title: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            watchface: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            updatedAt: ['', [Validators.minLength(1), Validators.maxLength(255)]],
            createdAt: ['', [Validators.minLength(1), Validators.maxLength(255)]],
        });

        // watch for changes and validate
        this.form.valueChanges.subscribe(data => {
            this.validateForm();
        }
        );
    }

    /**
     * validate the entire form
     */
    validateForm() {
        for (let field in this.formErrors) {
            // clear that input field errors
            this.formErrors[field] = '';

            // grab an input field by name
            let input = this.form.get(field);

            if (input.invalid && input.dirty) {
                // figure out the type of error
                // loop over the formErrors field names
                for (let error in input.errors) {
                    // assign that type of error message to a variable
                    this.formErrors[field] = this.validationMessages[field][error];
                }
            }
        }

        //this.validateAddresses();
    }

    //################################
    // datepicker
    //################################
    createAddress() {
        return this.fb.group({
            city: ['', Validators.minLength(3)],
            country: ['']
        });
    }

    public getDate(): number {
        return this.dt && this.dt.getTime() || new Date().getTime();
    }

    public today(): void {
        this.dt = new Date();
    }

    public d20090824(): void {
        this.dt = moment('2009-08-24', 'YYYY-MM-DD').toDate();
    }

    // todo: implement custom class cases
    public getDayClass(date: any, mode: string): string {
        if (mode === 'day') {
            let dayToCheck = new Date(date).setHours(0, 0, 0, 0);

            for (let i = 0; i < this.events.length; i++) {
                let currentDay = new Date(this.events[i].date).setHours(0, 0, 0, 0);

                if (dayToCheck === currentDay) {
                    return this.events[i].status;
                }
            }
        }

        return '';
    }

    public disabled(date: Date, mode: string): boolean {
        return (mode === 'day' && (date.getDay() === 0 || date.getDay() === 6));
    }

    public open(): void {
        this.opened = !this.opened;
    }

    public clear(): void {
        this.dt = void 0;
    }

    public toggleMin(): void {
        this.dt = new Date(this.minDate.valueOf());

        console.log(this.dt);
    }
}
`

watchface-detail.component.html

 ` <div class="container">

    <div class="navbar navbar-default">
        <div class="navbar-header">
            <a class="navbar-brand" href>Angular2 File Upload</a>
        </div>
    </div>

    <div class="row">

        <div class="col-md-3">

            <h3>Select files</h3>

            <div ng2FileDrop
                 [ngClass]="{'nv-file-over': hasBaseDropZoneOver}"
                 (fileOver)="fileOverBase($event)"
                 [uploader]="uploader"
                 class="well my-drop-zone">
                Base drop zone
            </div>

            <div ng2FileDrop
                 [ngClass]="{'another-file-over-class': hasAnotherDropZoneOver}"
                 (fileOver)="fileOverAnother($event)"
                 [uploader]="uploader"
                 class="well my-drop-zone">
                Another drop zone
            </div>

            Multiple
            <input type="file" ng2FileSelect [uploader]="uploader" multiple  /><br/>

            Single
            <input type="file" ng2FileSelect [uploader]="uploader" />
        </div>

        <div class="col-md-9" style="margin-bottom: 40px">

            <h3>Upload queue</h3>
            <p>Queue length: {{ uploader?.queue?.length }}</p>

            <table class="table">
                <thead>
                <tr>
                    <th width="50%">Name</th>
                    <th>Size</th>
                    <th>Progress</th>
                    <th>Status</th>
                    <th>Actions</th>
                </tr>
                </thead>
                <tbody>
                <tr *ngFor="let item of uploader.queue">
                    <td><strong>{{ item?.file?.name }}</strong></td>
                    <td *ngIf="uploader.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td>
                    <td *ngIf="uploader.isHTML5">
                        <div class="progress" style="margin-bottom: 0;">
                            <div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': item.progress + '%' }"></div>
                        </div>
                    </td>
                    <td class="text-center">
                        <span *ngIf="item.isSuccess"><i class="glyphicon glyphicon-ok"></i></span>
                        <span *ngIf="item.isCancel"><i class="glyphicon glyphicon-ban-circle"></i></span>
                        <span *ngIf="item.isError"><i class="glyphicon glyphicon-remove"></i></span>
                    </td>
                    <td nowrap>
                        <button type="button" class="btn btn-success btn-xs"
                                (click)="item.upload()" [disabled]="item.isReady || item.isUploading || item.isSuccess">
                            <span class="glyphicon glyphicon-upload"></span> Upload
                        </button>
                        <button type="button" class="btn btn-warning btn-xs"
                                (click)="item.cancel()" [disabled]="!item.isUploading">
                            <span class="glyphicon glyphicon-ban-circle"></span> Cancel
                        </button>
                        <button type="button" class="btn btn-danger btn-xs"
                                (click)="item.remove()">
                            <span class="glyphicon glyphicon-trash"></span> Remove
                        </button>
                    </td>
                </tr>
                </tbody>
            </table>

            <div>
                <div>
                    Queue progress:
                    <div class="progress" style="">
                        <div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': uploader.progress + '%' }"></div>
                    </div>
                </div>
                <button type="button" class="btn btn-success btn-s"
                        (click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
                    <span class="glyphicon glyphicon-upload"></span> Upload all
                </button>
                <button type="button" class="btn btn-warning btn-s"
                        (click)="uploader.cancelAll()" [disabled]="!uploader.isUploading">
                    <span class="glyphicon glyphicon-ban-circle"></span> Cancel all
                </button>
                <button type="button" class="btn btn-danger btn-s"
                        (click)="uploader.clearQueue()" [disabled]="!uploader.queue.length">
                    <span class="glyphicon glyphicon-trash"></span> Remove all
                </button>
            </div>

        </div>

    </div>

</div>`
rrubio commented 7 years ago

Having the same issue, any further luck with this @pangky24 ?

rrubio commented 7 years ago

Fixed my side by adding "FileUploadModule" to my module and importing it.

nebiljabari commented 7 years ago

If it can help I successfully passed this error. More info here

Steven-Harris commented 7 years ago

I am having the same issue

mhlulani commented 7 years ago

I've try to make this work with no luck, I'm not sure that even works. All comments suggests you do something that was never discussed in the documentation (hacking). It should not be so difficult to get the BASIC functions working.

I'm dropping this. I'll simply do file upload manually until there is a simpler solution available.

The Following manual solutions do work, but you may need to tweak some of it (I could not get the upload progress working correctly - shows 0% the skips over to 100% but the file uploads successfully )

https://www.thepolyglotdeveloper.com/2016/02/upload-files-to-node-js-using-angular-2 https://embed.plnkr.co/ozZqbxIorjQW15BrDFrg/ http://stackoverflow.com/questions/32423348/angular2-post-uploaded-file

matiasfessia commented 7 years ago

I have the same problem but importing the module like @rrubio says, works fine! Maybe it should be in the documentation.

adrianfaciu commented 7 years ago

FileUploadModule needs to be imported instead of adding the directives to the declarations array.