I have a scenario where I need to pass a list of different "components" to another angular component. I'm passing the list of components as an array using the #Input. How can I render those components in the HTML?
It would be helpful to see some code to have an idea about what you're trying to accomplish.
From the documentation, #Input()
An Input property is a settable property annotated with an #Input decorator. Values flow into the property when it is data bound with a property binding
An #Input() annotation is used for passing data. It's not used for passing components to another component.
To display another component inside another component, reference the nested component's selector inside the parent component. The selector is part of component metadata
selector: A CSS selector that tells Angular to create and insert an instance of this component wherever it finds the corresponding tag in template HTML. For example, if an app's HTML contains , then Angular inserts an instance of the HeroListComponent view between those tags.
app-hero-list.component.ts
Create a component and give a selector in the metadata.
#Component({
selector: 'app-hero-list',
templateUrl: './hero-list.component.html',
providers: [ HeroService ]
})
app.component.html
Then you can reference that selector as a pair of HTML tags in another component's template.
<app-hero-list></app-hero-list>
Have a look at the component metadata link referenced above and the Angular Tutorial for some more information about displaying components in other components.
If you need a more detailed answer, please update your question with a code example.
Related
In Angular, if we want to bind a property from outside for a custom component, we have to use "#Input" to kind of allow that property to be set from outside (i.e. from consuming component template)
Does EmberJS also have some sort of similar mechanism OR does it allow binding directly from the template (hbs) without adding/marking anything in the component JS? Is there any difference when it comes to Ember Octane V/s the earlier versions of Ember?
yes it allows binding from outside the component without adding anything to the component js
in the component hbs file
<p>{{#attribute}}</p>
from outside
<MyComponent #attribute="attributeValue"/>
also you can get the binded attribute from component js
#tracked mycomponentAttribute = this.args.attribute;
in the component hbs file
<p>{{this.mycomponentAttribute}}</p>
no you don't necessarily have to add the input tag but you have to declare the property inside the component you are trying to pass the property to.
{{#each model as |post|}}
{{blog-post title=post.title body=post.body}}
{{/each}}
the blog-post component, define a property named title and this should work.
I have a component called button-widget and it is registered globally.
Vue.component('button-widget', {
template: `<button>My Button</button>`
})
Now, how can I delete this component permanently?
I am not talking about v-if or $destroy() -- I just want to completely remove this component in such a way that it was never defined so that for example, I get this warning: Unknown custom element: <button-widget> - did you register the component correctly? For recursive components, make sure to provide the "name" option..
There is no public API to do this.
The correct solution is not to register it globally in the first place and instead just use it on a per-component basis by adding it to the components option of each component you want to use it in.
Otherwise you can unregister it like this:
delete Vue.options.components['button-widget']
I'm facing a problem which has been mentioned some times ago but those solutions like this one:
What is the proper use of an EventEmitter?
I want to take this example on the shared link to keep it easy:
Let's start:
First, I have those routes in app.module.ts:
{path: 'dash/:project_id', component: DashProject, children: [
{path: '', component: null},
{path: 'task/form', component: TaskForm},
{path: 'task/:task_id', component: TaskView}
As you can see, DashProject is my parent and those other are children. I've also included to the template of DashProject the required
<router-outlet></router-outlet>
part to include children there.
But in this mentioned example I need to include
<child (notifyParent)="getNotification($event)"></child>
Now I made it like this in my parent template:
<child (notifyParent)="getNotification($event)"></child>
<router-outlet></router-outlet>
Problem: When I add <child (notifyParent)="getNotification($event)"></child> to my parent template the child component is already included to the parent, even it's not called by URL routing. When I remove the part, the interaction between parent-child doesn't work anymore.
If I add those to the child template I get a never ending loop and crash.
Can anyone see my problem or know what is causing this error? I saw some examples on the net, like the shared one above, and all were using a similar solution, but it won't work for me.
Thanks in advance!
Kind regards, yadbo
It looks like you may be merging two different techniques.
Use routing when you want to route to a component. For example, route to the dash project page or the task form page. Normally routed components have no selector and are not directly referenced in the HTML. Rather, they appear in the <router-outlet>.
Use nested components when you want to use a component as a child component of another component. For example, display a set of stars instead of a rating in the project page. The nested component must have a selector and that selector is used in the HTML (like your <child> example.)
When using nested components, you can use #input and #output to communicate between the parent and child.
When using routed components, you can communicate between the components by passing parameters (required, optional, or query parameters), by using a shared resolver, or by setting up properties in a service.
Thanks you #DeborahK for your hint, that was I was missing.
Now I'm using a shared service for solving this problem, I'm passing a callback to the shared service which I call from the child.
Here is an example, at least the idea, how it works:
export class SharedService {
private callback:any = null;
public constructor() {
}
public getCallback() {
return this.callback;
}
public setCallback(call) {
this.callback = call;
}
}
Parent:
this._shared.setCallback(this.test.bind(this));
Child:
this._shared.getCallback()();
And yes, it works :)
In our Angular 2 application we use the Combobox component from Kendo. This component is wrapped into a component created dynamically during the runtime. The code of the creation is very simple :
let factory = this.resolver
.resolveComponentFactory(ComboboxComponent);
nextTo.createComponent(factory);
The nextTo variable represents where Angular has to create the component.
#ViewChild('container', { read: ViewContainerRef })
container: ViewContainerRef;
The container variable represents a div in the HTML Template.
NB : the component is created during the ngAfterViewInit event. No errors are thrown during the creation.
The Kendo component is properly instanciated and initialized, but when we affect data after the creation, the component seems to don't recognize the binding, and do nothing. Any ideas ?
HTML of the component :
<kendo-combobox [data]="listItems"></kendo-combobox>
TypeScript :
#Component({
templateUrl: `combobox.component.html`,
selector: 'combobox',
styleUrls: [
'combobox.component.css'
]
})
export class ComboboxComponent extends FieldComponent {
public listItems: Array<string> = ["X-Small", "Small", "Medium", "Large", "X-Large", "2X-Large"];
}
NB2 : FieldComponent is an abstract class we use for global actions for all of our components.
EDIT1 : I finally manage to find what's the problem, but I can't say what's wrong. When I inspect the DOM, I can see that a <div role='combobox'> is hidden, and this is the combobox which contain all data. So why have I a second combobox shown with no data ?
I suspect that change detection for the component is not triggered in this case.
createComponent returns a ComponentRef which has the change detector associated with that component. You can try calling detectChanges() of that ChangeDetectorRef once the dynamic component is created.
I've found what cause this strange behavior. Due to the very first beginning of the project, we use Kendo JQuery for our components, and we use kendo.all.js. I don't really know why, but it seems that kendo.all.js interfers into the kendo-combobox HTML template of the new Angular component, and it inject some intempestive HTML which cause the strange behavior.
I do have my component called Grid. Inside this component I load JSON data from server and i render them. They are mostly string and integers. Sometimes the JSON contains HTML like <strong>myvalue</stong> so I render the data with three brackets {{{ and }}}.
The thing is when the HTML is not pure HTML but component like <my-component my-param="1"></my-component>. How to tell to Vue.js to render this coponent? All I get is the HTML purely printed into grid.
Thanks
You need to compile again that piece of code you've loaded from remote.
ps: I will use jQuery to manipulate the DOM.
Inside this component I load JSON data from server and i render them.
I'll assume you have a function named "loadAndRenderFromServer()", please adapt the code below to fits you.
Eg: If your grid has the markup <div id='grid'>
// vuecomponent.js
export default {
[...]
methods: {
loadAndRenderFromServer() {
// first, load remote content and insert into #grid
// now, compile
this.$compile($("#grid").get(0));
}
},
[...]
}
You may need to use "decompile" if your component starts to duplicate the loaded content. Check into VueJS docs for compile and decompile methods.
Using v-html (which is equivalent to {{{}}}) will not render what's inside it if it's a component.
Instead try to use <slot> in your parent template.
Otherwise, if you want dynamic components you need to use <component> and if you want content inside those dynamic component you need to use <slot>s.
I would suggest you to use something like
<component :is="myComponent" />
and inside the models of those components put some <slot>s to insert arbitrary content.