One of the biggest moves we’ve had to make recently is using Angular Components. We’ve found them to be extremely effective at reducing workload.
A part we got stuck on recently was regarding binding functions to the component from the parent controller. Each component can have its own controller, so you can put all sorts of nice events within the controller, but sometimes you need to access a tool from outside. We had this issue with a command bar, where we had a Save button. We didn’t want to rewrite the save function in both the form’s controller AND in the component.
Often, we try to make components completely stand-alone. For example, if we want to show the commission breakdown of a sales order, rather than having the parent component look up the sales commission breakdowns in the API, we inject our sales API factory into the component and let it work it out on its own. That way, we just add the component and the sales order# as a binding and it just “works”. You can drop it anywhere on any form in the entire site. It’s very nice.
However, we’ve also been trying to avoid injecting custom services into components to ensure that they can be used in multiple systems. That makes nice components, but it means that the “work” has to be done in the parent. When doing a rebuild, where you’re replacing sections of an angular controller/partial page with a series of controllers, it’s actually much easier to keep all the functions at the top and just pass them down as needed.
In this case, a command bar with a save button. It’s not the only place on the form, so we don’t want to code the Save() function multiple times, and we might be using it on 3 different forms, so we obviously couldn’t inject the same factory! The result: Pass the functions to the component.
Here’s how we did it:
app.component("jobCommandBar", { template: ` ` , bindings: { saveCommand: '&' }, controller: jobCommandBar, controllerAs: 'vm' });
The controller, (trimmed down to get rid of a lot of other code) is like this:
export class jobCommandBar { public saveCommand: () => any; }
This command bar has a ton of stuff in it that you can’t see, but what you’re looking at is how we got a FUNCTION into that component. We often want to intercede the function and test a few things. In this version, for example, we had several additional “if-thens” to validate things before the save command was initiated. By making all the bindings public classes in TypeScript, we can modify and validate within the component before initiating commands and functions.
Now look at how we use it in the HTML:
That’s it. DO NOT FORGET THE () on your function.
You thought you were done?
Here’s the deal. Angular 2 is going to be focused heavily on controlling 2 way binding. Basically components should have an in and an out. That’s it. Right now, you can do this:
app.component("jobCommandBar", { template: ` ` , bindings: { someValueToComeFromParent: '<' }, controller: jobCommandBar, controllerAs: 'vm' });
where "someValueToComeFromParent" would be included as a value in the tag
If you wanted to keep that value in sync, you could change the "<" to a "=". But that is super wasteful if you don't really really need it to be in live sync. Usually, there's an event where you've got your numbers and now you want to push them back up to the parent.
don't say root scope. no... bad scope.
Until you get to angular 2, we can accomplish this with function event parameters. Check it out:
We use typescript, so we start with the controller:
export class childComponent{ public dataToReceive:($event:any) => any; sendMyData(){ // some example info let obj={}; obj.value1="ABC"; obj.value2="DEF"; this.dataToReceive({$event: {myDataIsInHere: obj}}) } }
What we did was make a function that we're going to use in our childComponent that is triggered with a button. It is going to make a fake object, pop some stuff in it and send it to the bound function.
In the component declaration, we just bind it like any other function:
.component('childComponent', { template: `
So, in the parent controller, the parameter will be the data from the child control.
Once you get the hang of it, it's easy. Trying to figure it out took us a while!
[disqus]