简体   繁体   中英

Can't bind to 'ngFormControl' since it isn't a known native property

EDIT: the angular 2 dropdown multiselect hasnt been updated for angular 2 rc 4 because it has old syntax: [ngFormControl]="search" and import {Control} from 'angular2/common' and I have been trying to update the source code syntax of angular 2 dropdown multiselect to make it work

I'm trying to use angular 2 dropdown multiselect , just trying to get the most basic demo up and running.

But when I try to load the page I get this error:

Can't bind to 'ngFormControl' since it isn't a known native property ("" class="form-control" placeholder="{{ texts.searchPlaceholder }}" aria-describedby="sizing-addon3" [ERROR ->][(ngFormControl)]="search">

Why do I get this error and how can I fix it?

Here is the relevant information:

folder structure:

在此输入图像描述

my component that depends on the angular 2 dropdown multiselect

import { Component } from '@angular/core';
import { MultiselectDropdown, IMultiSelectOption } from 'angular2-multiselect/src/multiselect-dropdown';
@Component({
   selector: 'multiselect',
   templateUrl: 'app/shared/multiselect.component.html',
   directives: [MultiselectDropdown]
})
export class MultiselectComponent {
    private myOptions: IMultiSelectOption[] = [
        { id: 1, name: 'Option 1' },
        { id: 2, name: 'Option 2' },
    ];
}

The ts file of angular 2 dropdown multiselect is correctly being transpiled to js.

js file structure:

在此输入图像描述

the source code of angular 2 dropdown multiselect :

/*
 * Angular 2 Dropdown Multiselect for Bootstrap
 * Current version: 0.1.0
 * 
 * Simon Lindh
 * https://github.com/softsimon/angular-2-dropdown-multiselect
 */

import {Component, Pipe, OnInit, HostListener, Input, ElementRef, Output, EventEmitter} from '@angular/core';
import {Control} from '@angular/common'
import {Observable} from 'rxjs/Rx';

export interface IMultiSelectOption {
    id: number;
    name: string;
}

export interface IMultiSelectSettings {
    pullRight?: boolean;
    enableSearch?: boolean;
    checkedStyle?: 'checkboxes' | 'glyphicon';
    buttonClasses?: string;
    selectionLimit?: number;
    closeOnSelect?: boolean;
    showCheckAll?: boolean;
    showUncheckAll?: boolean;
    dynamicTitleMaxItems?: number;
    maxHeight?: string;
}

export interface IMultiSelectTexts {
    checkAll?: string;
    uncheckAll?: string;
    checked?: string;
    checkedPlural?: string;
    searchPlaceholder?: string;
    defaultTitle?: string;
}

@Pipe({
    name: 'searchFilter'
})
class SearchFilter {
    transform(options: Array<IMultiSelectOption>, args: Array<string>): Array<IMultiSelectOption> {
        return options.filter((option: IMultiSelectOption) => option.name.toLowerCase().indexOf(args[0].toLowerCase()) > -1);
    }
}

@Component({
    selector: 'ss-multiselect-dropdown',
    pipes: [SearchFilter],
    styles: [`
        a { outline: none; }
    `],
    template: `
        <div class="btn-group">
            <button type="button" class="dropdown-toggle btn" [ngClass]="settings.buttonClasses" (click)="toggleDropdown()">{{ getTitle() }}&nbsp;<span class="caret"></span></button>
            <ul *ngIf="isVisible" class="dropdown-menu" [class.pull-right]="settings.pullRight" [style.max-height]="settings.maxHeight" style="display: block; height: auto; overflow-y: auto;">
                <li style="margin: 0px 5px 5px 5px;" *ngIf="settings.enableSearch">
                    <div class="input-group input-group-sm">
                        <span class="input-group-addon" id="sizing-addon3"><i class="fa fa-search"></i></span>
                        <input type="text" class="form-control" placeholder="{{ texts.searchPlaceholder }}" aria-describedby="sizing-addon3" [(ngFormControl)]="search">
                        <span class="input-group-btn" *ngIf="searchFilterText.length > 0">
                            <button class="btn btn-default" type="button" (click)="clearSearch()"><i class="fa fa-times"></i></button>
                        </span>
                    </div>
                </li>
                <li class="divider" *ngIf="settings.enableSearch"></li>
                <li *ngIf="settings.showCheckAll">
                    <a href="#" role="menuitem" tabindex="-1" (click)="checkAll()">
                        <span style="width: 16px;" class="glyphicon glyphicon-ok"></span>
                        {{ texts.checkAll }}
                    </a>
                </li>
                <li *ngIf="settings.showUncheckAll">
                    <a href="#" role="menuitem" tabindex="-1" (click)="uncheckAll()">
                        <span style="width: 16px;" class="glyphicon glyphicon-remove"></span>
                        {{ texts.uncheckAll }}
                    </a>
                </li>
                <li *ngIf="settings.showCheckAll || settings.showUncheckAll" class="divider"></li>
                <li *ngFor="#option of options | searchFilter:searchFilterText">
                    <a href="#" role="menuitem" tabindex="-1" (click)="setSelected($event, option)">
                        <input *ngIf="settings.checkedStyle == 'checkboxes'" type="checkbox" [checked]="isSelected(option)" />
                        <span *ngIf="settings.checkedStyle == 'glyphicon'" style="width: 16px;" class="glyphicon" [class.glyphicon-ok]="isSelected(option)"></span>
                        {{ option.name }}
                    </a>
                </li>
            </ul>
        </div>
    `
})
export class MultiselectDropdown implements OnInit {
    @Input() options: Array<IMultiSelectOption>;
    @Input() settings: IMultiSelectSettings;
    @Input() texts: IMultiSelectTexts;
    @Input('defaultModel') selectedModel: Array<number> = [];
    @Output('selectedModel') model = new EventEmitter();
    @Output() selectionLimitReached = new EventEmitter();
    @HostListener('document: click', ['$event.target'])
    onClick(target) {
        let parentFound = false;
        while (target !== null && !parentFound) {
            if (target === this.element.nativeElement ) {
                parentFound = true;
            }
            target = target.parentElement;
        }
        if (!parentFound) {
            this.isVisible = false;
        }
    }

    private numSelected: number = 0;
    private isVisible: boolean = false;
    private search = new Control();
    private searchFilterText: string = '';
    private defaultSettings: IMultiSelectSettings = {
        pullRight: false,
        enableSearch: false,
        checkedStyle: 'checkboxes',
        buttonClasses: 'btn btn-default',
        selectionLimit: 0,
        closeOnSelect: false,
        showCheckAll: false,
        showUncheckAll: false,
        dynamicTitleMaxItems: 3,
        maxHeight: '300px',
    };
    private defaultTexts: IMultiSelectTexts = {
        checkAll: 'Check all',
        uncheckAll: 'Uncheck all',
        checked: 'checked',
        checkedPlural: 'checked',
        searchPlaceholder: 'Search...',
        defaultTitle: 'Select',
    };

    constructor(
        private element: ElementRef
    ) { }

    ngOnInit() {
        this.settings = Object.assign(this.defaultSettings, this.settings);
        this.texts = Object.assign(this.defaultTexts, this.texts);
        this.updateNumSelected();
        this.search.valueChanges
            .subscribe((text: string) => {
                this.searchFilterText = text;
            });
    }

    clearSearch() {
        this.search.updateValue('');
    }

    toggleDropdown() {
        this.isVisible = !this.isVisible;
    }

    modelChanged() {
        this.updateNumSelected();
        this.model.emit(this.selectedModel);
    }

    isSelected(option: IMultiSelectOption): boolean {
        return this.selectedModel.indexOf(option.id) > -1;
    }

    setSelected(event: Event, option: IMultiSelectOption) {
        var index = this.selectedModel.indexOf(option.id);
        if (index > -1) {
            this.selectedModel.splice(index, 1);
        } else {
            if (this.settings.selectionLimit === 0 || this.selectedModel.length < this.settings.selectionLimit) {
                this.selectedModel.push(option.id);
            } else {
                this.selectionLimitReached.emit(this.selectedModel.length);
                return;
            }
        }
        if (this.settings.closeOnSelect) {
            this.toggleDropdown();
        }
        this.modelChanged();
    }

    getTitle() {
        if (this.numSelected === 0) {
            return this.texts.defaultTitle;
        }
        if (this.settings.dynamicTitleMaxItems >= this.numSelected) {
            return this.options
                .filter((option: IMultiSelectOption) => this.selectedModel.indexOf(option.id) > -1)
                .map((option: IMultiSelectOption) => option.name)
                .join(', ');
        }
        return this.numSelected + ' ' + (this.numSelected === 1 ? this.texts.checked : this.texts.checkedPlural);
    }

    updateNumSelected() {
        this.numSelected = this.selectedModel.length;
    }

    checkAll() {
        this.selectedModel = this.options.map(option => option.id);
        this.modelChanged();
    }

    uncheckAll() {
        this.selectedModel = [];
        this.modelChanged();
    }

}

Try to use version 0.2.0: angular-2-dropdown-multiselect

Quick guid:

  1. Install as local npm package (npm install angular-2-dropdown-multiselect --save-dev).
  2. Add to my component file: import { IMultiSelectOption, IMultiSelectSettings, IMultiSelectTexts } from '../../node_modules/angular-2-dropdown-multiselect/src/multiselect-dropdown';.
  3. in node_modules/angular-2-dropdown-multiselect/src/multiselect-dropdown.ts, add export in front of class MultiSelectSearchFilter so it can be imported in my module file in next step.
  4. Add to my module file: import { MultiselectDropdown, MultiSelectSearchFilter } from '../../node_modules/angular-2-dropdown-multiselect/src/multiselect-dropdown'; Note the README says MultiselectDropdownModule, but I think it's a typo and should be MultiselectDropdown (PR).
  5. Add MultiselectDropdown and MultiSelectSearchFilter to @NgModule declarations.

Guid reference from issue: issue 14

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM