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 :)
Related
I has received a requirement from my boss which is analyzing existing code of my colleagues. I encounter some of weird code like this:
class Parent extends React.Component {
methodA () { ... }
methodB () { ... }
render () {
<div>
...other lines of code
<Child parent={this} />
</div>
}
}
And inside of child component, they use this.props.parent.methodA() and other parent methods like so instead of passing function as props.
I am proposing a rule not to use that pattern. Because that's pretty unreadable and the behaviors of those functions might be sometime unpredictable.
I am wondering besides things which i am talking about, does this pattern could run into any performance issues?
Thanks in advance.
Most usual scenario is when child calls some method from parent on click event, for example.
In that case you pass just that method.
<Child doSomethingMethod={methodA} />
and then in Childs render method:
<button onClick={doSomethingMethod} />
I can’t think of an example where child should be aware of parents implementation.
In your case, parent should always have methodA and if you ever decide you want to change parent structure, you need to change child as well.
On the other hand, when you pass just a method, your child doesnt care where the parent got that method from. So, its loosely coupled where each component handles itself only and receives only those params from other component that it needs (including functions).
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 have a problem working with two components (pop ups) in which i have to send data from a chlid component to another one (parent) who doesn't have an event to extract this data.
logically i have to find a sort of function that makes the parent listen to the changes made in the child.
The Changes have to appear in the same time in both components.
Could any one help ?
The answer is in your question. You need an Output property, which is the Angular generalization of a JS event.
In your child component:
class ChildComponent {
#Input() someProperty: string;
#Output() dataChanged = new EventEmitter<string>();
whenSomethingHappensInChild() {
this.dataChanged.emit('something');
}
}
In your parent template:
...
<app-child [someProperty]="'someValue'" (dataChanged)="doSomething($event)"></app-child>
...
And in you Parent code:
class ParentComponent {
...
doSomething(theValue: string) {
// TA-DAA! you have the value.
}
...
}
Please, do yourself a favor and READ THE DOCS, or, better, a book ;)
In particular:
https://angular.io/guide/architecture-components has a full overview of the basics of binding, which this problem falls into.
Have a nice day.
Yes, you can use a shared BehaviorSubject to push values and both components have to subscribe to get this changes
Problem Solved: I used the #Host() tag to get the current instance of the Parent component and access the methode that changes it's attributes.
Here is what you should do.
First:
You should declate your parent component in the child
parent:ParentComponent;
Second :
you should pass your current parent instance to your new declaration in the constructor
constructor(#Host() currentParent:ParentComponent){
this.parent=currentParent
}
Third:
Now try just to access the methods and attributes in the parent components
changeParentAttribute(){
this.parent.iAmInTheParent();
}
I hope you find this helpful
I have a following function inside a child component:
reload() {
clearInterval(this.points);
this.initiateInterval();
this.redrawImages();
}
It's redrawing few images on window.resize event.
But in the parent component, I have a button menu-burger which shrunks the window. I want to bind to this button the reload() function from the child component.
This is my button from the parent component:
<button class="collapseMenuIcon" (click)="toggleMenu()">
I was looking for other questions about it on Stack, but in my case - this reload function uses a lot of stuff in this child component.
Also few solutions from other questions are deprecated, because Angular2 changes often.
Thank you in advance, I will upvote all answers.
A shared Service is a very good option. Just to throw another option out there, depending on your use case, you can just use a Subject between the parent and child without the service, if you want.
Declare Subject in child:
import { Subject } from 'rxjs/Subject';
public static fireEvent: Subject<boolean> = new Subject();
and subscribe in your constructor:
constructor(....) {
MyChildComponent.fireEvent.subscribe(res => {
this.reload();
});
}
And in your parent:
import { MyChildComponent } from './my-path';
and on your button click, tell child to fire reload-method:
toggleMenu() {
MyChildComponent.fireEvent.next(true);
}
There are several ways to communicate between components. I personally use a service for that purpose, and it works great for me.
Read here: https://angular.io/docs/ts/latest/cookbook/component-communication.html
The last example (the service one) is the one that I use, and is quite simple to implement.
Edit:
Using services allow you to have independent components, being able to use them in other parts of the app. You also can send/receive data and the communication is both sides. I strongly recommend this method.
In anticipation of Routable Components coming soon, I'm attempting to use Components wherever possible in my Ember 2.0 application. I'm running into a confusing issue where I cannot access the parent component's properties from the template when provided in block form. It may be very well that this isn't possible, but wanted to be sure. Here's an example:
Template:
// templates/approvals.hbs
{{#x-secure/schedule/approvals}}
{{#x-secure/layout/full sectionTitle=sectionTitle sectionDescription=sectionDescription}}
...
{{/x-secure/layout/full}}
{{/x-secure/schedule/approvals}}
Component Template:
// templates/components/schedule/approvals.hbs
{{yield}}
Component:
// components/schedule/approvals.js
import Ember from 'ember';
export default Ember.Component.extend({
/////////////////////////////////////
// PROPERTIES
/////////////////////////////////////
sectionTitle: 'Scheduling: Approvals',
sectionDescription: 'Lots of magical , fanstastic stuff.'
});
The issue I'm having is that I'm unable to access sectionTitle and sectionDescription from the parent component (approvals) and pass it into the layout/full component. However, if I remove code from the block of the component and move it to the templates/components/schedule/approvals.hbs template, it works as expected. Is it just not possible to access a parent component's properties from the block form of a component?
Thanks!
It is not possible indeed. The component's properties are available in the component's template, but not in the template that instantiates the component.
If you need the component to make things available, it should yield them explicitly:
// templates/components/schedule/approvals.hbs
{{yield sectionTitle sectionDescription}}
And using the component:
// templates/approvals.hbs
{{#x-secure/schedule/approvals as |title description|}}
{{#x-secure/layout/full sectionTitle=title sectionDescription=description}}
...
{{/x-secure/layout/full}}
{{/x-secure/schedule/approvals}}
Notice the as |x y ...| notation to assign names to yielded values.
Anything may be yielded this way, including this (be careful with that though, that breaks encapsulation) and actions.