Reputation: 6006
I am working on my Ionic 2 component ionic2-autocomplete, which was originally developed for RC.4 and earlier versions, and now I am trying to migrate it to Angular 2 final.
As part of the original design, I let the developers overwrite the default template by using a custom decorator AutoCompleteItem
which accepts template
or templateUrl
.
The source code of this decorator could be found here.
As you can see, I used the decorator in order to preserve some of the attributes required for my component, alongside letting the users design the component for their own needs.
Now, following the exact same steps I wrote in the docs, I tried to implement a custom template by using:
import {AutoCompleteItem, AutoCompleteItemComponent} from 'ionic2-auto-complete';
@AutoCompleteItem({
template : `<img src="build/images/flags/{{data.name}}.png" class="flag" /> <span [innerHTML]="data.name | boldprefix:keyword"></span>`,
})
export class CompTestItem extends AutoCompleteItemComponent{
}
Which worked perfectly on the earlier versions (I also added the CompTestItem
to the declerations
array).
But for some reason, I now encounter the following exception:
polyfills.js:3 Unhandled Promise rejection: Template parse errors: More than one component: AutoCompleteItemComponent,CompTestItem ("
[ERROR ->] ; Task: Promise.then ; Value: Error: Template parse errors:(…) Error: Template parse errors: More than one component: AutoCompleteItemComponent,CompTestItem ("
[ERROR ->]http://localhost:8101/build/main.js:19480:19) at RuntimeCompiler._compileTemplate (http://localhost:8101/build/main.js:27855:51) at http://localhost:8101/build/main.js:27777:83 at Set.forEach (native) at compile (http://localhost:8101/build/main.js:27777:47) at t.invoke (http://localhost:8101/build/polyfills.js:3:13400) at e.run (http://localhost:8101/build/polyfills.js:3:10787) at http://localhost:8101/build/polyfills.js:3:8889 at t.invokeTask (http://localhost:8101/build/polyfills.js:3:14029) at e.runTask (http://localhost:8101/build/polyfills.js:3:11389)o @ polyfills.js:3r @ polyfills.js:3i @ polyfills.js:3 polyfills.js:3 Error: Uncaught (in promise): Error: Template parse errors:(…)o @ polyfills.js:3r @ polyfills.js:3i @ polyfills.js:3
I really don't have a clue why. Could anyone have a clue why this custom decorator wont work on this version of Angular? And why does it say that I have more than one component?
Thanks!
Upvotes: 1
Views: 275
Reputation: 209004
To explain my comments above more clearly. Look at your decorator
export function AutoCompleteItem( config: AutoCompleteItemMetadata ) {
return function(cls: any) {
const _reflect: any = Reflect;
let annotations = _reflect.getMetadata('annotations', cls) || [];
let extendedConfig: any = config;
extendedConfig.selector = 'ion-auto-complete-item';
annotations.push(new Component(extendedConfig));
_reflect.defineMetadata('annotations', annotations, cls);
return cls;
};
}
You're setting the selector on every component to ion-auto-complete-item
. So in this situation
@AutoCompleteItem({
template: defaultTemplate
})
export class AutoCompleteItemComponent {}
@AutoCompleteItem({})
export class ExtendedComponent extends AutoCompleteComponent {}
You now have two components with the same selector. Now this alone doesn't matter. But when the two of them get into the same room together, Angular can't determine which one to use.
Now this may not need a problem in earlier RC4 because the confinement was smaller than it is now. Before you used directives
which is only scoped to the component
@Component({
directives: [ AutoCompleteItemComponent ]
})
class SomeComponent {}
It's probably rare that you would use the AutoCompleteItemComponent
and ExtendedComponent
in the same component; so no conflict.
But not that we use modules, the scope of the component becomes a little wider, and this leaves room for more conflict.
Maybe you have a shared module that you import into another module
@NgModule({
imports: [ FormsModule, CommonModule ],
declarations: [ AutoCompleteItemComponent ],
exports: [ AutoCompleteItemComponent ]
})
class SharedModule {}
@NgModule({
imports: [ SharedModule ],
declarations: [ ExtendedComponent, ComponentThatUsesExendedComponent ]
exports: [ ComponentThatUsesExtendedComponent ]
})
class OtherModule {}
In the above case, you will get the error, because now the AutoComponentItemComponent
and ExtendedComponent
are in the same room together. Angular can't figure out which one to use inside the ComponentThatUsesExendedComponent
, so you get the error
More than one component AutoCompleteItemComponent, ExtendedComponent
At this point I'm not sure what you can do to fix this but to just make sure that the two components are never in the same room together, either explicitly or implicitly. What makes it even more difficult is that component classes can only be declared in one module.
Upvotes: 1