Hi i am very new to angularjs web development with typescript and really stuck with a problem. I dont think it should be a hard problem yet i have spent two days on it.
I am trying to figure out how i can pass the value of an ng-repeat from a list to a child component when it's being constucted or initiated.
What i mean is, if i have a list([1, 2, 3, 4]) from the parent component that is used to generate 4 child components is there a way for each of the child components to assign a variable "id" to the value associated to the value of the repeat.
for example
<span ng-repeat=variable in list>
<child-tag></child-tag>
</span>
Is it possible to somehow pass the variable into the constructor of the component from the tags or something?
Just to reiterate, I have coded this using typesccript with angularjs not angular 2.
Cheers in advance for the help.
And sorry in advance for what is probably a very simple answer but cant find it anywhere.
You can pass the data from parent to child component using Input.
Inputs should be using < and # bindings. The < symbol denotes one-way bindings which are available since v1.5.
=: Two way binding. It uses dirty checking and can cause latency. It also watches bound properties in the component scope.
So if you need to pass some data to child component, you need to bind some attribute value to it . Ex:
<span ng-repeat="variable in list">
<child-tag variable-name="variable.name" ></child-tag>
</span>
Inside your child component declaration bind these values so that you can access them:
angular.module('myApp', []).component('childComponent', {
bindings: {
variableName: '<'
},
controller: ....
You can access these values inside your component class using: this.variableName
You can choose to have one way or two binding as needed and can have as many objects/attributes passed to child as you want.
Related
Is there a way to dynamically add a 2 way binding [(somemodel)] property to a Host element in Angular 4 ?
<my-comp></mycomp>
We would like to replace the above markup to look like
<my-comp [(somemodel)]="modelvalue" ></mycomp>
dynamically at run time. We are aware the #HostBinding does not support this, as the most common examples we have seen are adding class or attributes to host.
Is there any way to replace the host element like this using Angular 4 ?
We are open to dynamically loading templates/components if someone can point us to the right direction.
In Angular 1, we used to replace the host element markup with our text and do a $compile(scope). Is there a similar approach in Angular 4 using dynamic loading ?
I think what you're looking for is #Input in Angular 4. It allows you to define a variable on your component and receive it's value from the HTML. Here are the Angular Docs on Input/Output
And a quick example
In your component, import 'Input' from Angular Core
import { Input } from '#angular/core';
Then, define your input variable. Here, I'm for a loading variable that is a boolean.
#Input() loading:boolean = false;
Then, in your HTML define the binding.
<loader [loading]="loading"></loader>
Remember that the 'loading' inside of the brackets will match the name of your input variable.
I got a component hierarchy that looks a bit like this:
#Component({
...
})
export class A {
constructor(private _serviceThatDeliversData: Service){}
getData(): Array<DataItem> {
return this._serviceThatDeliversData.getData();
}
}
html:
<b-selector [data]="getData()"></b-selector>
Child component:
#Component({
selector: 'b-selector'
...
})
export class B {
#Input() data: Array<DataItem>;
}
html:
<ul>
<li *ngFor="let item of data">
<c-selector [item]="item"></c-selector>
</li>
</ul>
So I got a parent component 'A' that receives data from a service. The serviceThatDeliversData creates the DataItem list every time it receives data from a websocket. This list is then passed down to 'B' where every list entry is used as a base for sub components ('C', I omitted the C component here cause it basically just presents the input data 'item').
My problem now is the following:
Since the list changes every time the service gets an update, the whole list of C components + the B component is newly created. I assume because the DataItem list changes completely Angular notices them as new entries (?) and the list as a new one itself (?)
However in reality it might very well be that only one item was added or removed or just a field has changed in one of the items. So only one C component would needed to be removed/added/updated.
Since that is the case any animations happening in the view in any of the C components stop and start again once the list is recreated. That plus some other side effects I would like to avoid.
So my question is, is there a way to let Angular only update the C components which relate to a DataItem that actually changed internally AND the ones that were added or removed to/from the list, but leave the ones that have not changed untouched?
I have searched for a while and found that one could use changeDetection: ChangeDetectionStrategy.OnPush, however I have not found a working example (with a changing array and changing array elements (internally)) that would help me with my problem.
I assume one could store a copy of the list in 'B', check the changes manually and then react to them - which could also be done with an animation to signal the user which entry was removed or added - however that would require a way to stop Angular from updating (recreating) 'B' and the 'C' components at all. I take it using the same array (clearing it and repopulating it with the new entries) might work.
But I'd still like to know if this could be possible via raw Angular mechanisms.
The changedetection strategy OnPush only picks up changes to values decorated with the Input-decorator and only if the reference of the value changes.
For example myArray[1] = 'a'; only mutates the array and no new reference is created, therefore angular with OnPush strategy wouldn't pick up the change. You have to clone the array and make the change to create a new array reference.
Your problem with angular recreating the elements inside an ngForOf directive is descriped in another answer of me. Read the note at the end of the answer.
Using Angularjs 1.5, I have been having trouble making a D3.js graph that's defined in one component display on a page that relies on a different one. I'm new to Angular, and while I think the answer is buried somewhere in the official documentation's example of a component tree, I wasn't able to completely follow the logic.
My goal is to make the graph defined in graphController, and make it appear as accessed by requests.template.html.
Trying to inject it into requests.component like I would a directive gave me an unknown provider error
I inherited the setup from someone else (and would prefer to leave the protect structure the way it is), and it more or less looks like this:
requests.module.js
angular.module("requests", []);
requests.component.js
angular.module('requests').component('requests', {
templateURL: 'Bindings/Templates/requests.html',
controller: function requestsController($scope) {
[code]
}
}
requests.template.html
//where I'd like to be able to access the controller from the graphs component
graphs.module.js
angular.module('graphs', []);
graphs.component.js
angular.module('graphs').component('graphs', {
templateURL: '/Bindings/Templates/graphs.template.html',
controller: function graph() {(code for d3 graph)};
}
graphs.template.js
{{$ctrl.graph()}}
//this page is just a placeholder to see the graph until I can view it on requests' page
Any help you can give or ways to think about how I should thread this controller call through would be great. Thanks!
If you are wanting the graph to display in the requests component then you can just insert the component element tag within the requests template. For example, in the Bindings/Templates/requests.html insert:
<div class="stuff-to-wrap-graph">
<graphs></graphs>
</div>
Once you have created a component, think of it like a unique html element that you can insert anywhere, including within other components. You would normally only want direct access to the controller of another component if it was a tightly coupled child of a parent, eg. an individual tab within a tabs component that needs to talk to the parent tab container.
I am using ng-repeat to populate data in a table so far so good. What i am trying to accomplish is to use a button and change it's text according to the userId (cust.id). I am trying to understand how to use a $scope inside a repeat method and modify it separately from the other elements.
On the following demo when i click to button with (userid value = 1) then i would like to change the specific button text and NOT every button in my ng-repeat
<button ng-click="perLineText(cust.id)">{{buttonText}}</button>
Live Demo
I am trying to figure out how to handle specific elements in my ng-repeat. Any help much appreciated.
You can do that by just using the this in you controller function instead of $scope.
$scope.perLineText = function(customerId){
if (customerId === 1) {
this.buttonText = 'Stop';
};
See the updated fiddle http://jsfiddle.net/u5swjwv1/
On a click callback this points to the scope of nested repeat element. If you use $scope you are actually referring to the parent scope object.
Look at this explanation too 'this' vs $scope in AngularJS controllers
A good way to handle this problem is using $index. Just pass it when calling your perLineText($index) function so you know which row you are in. Now you can simply work with the appropriate index object in your array which might my $scope.customers[index]
You can also use the ng-bind="perLineText(cust.id)" instead of the {{buttonText}} so the ng-click will toogle something and the perLineText will return Start or Stop.
I have an angular-rails resource with a property that consists of irregular data that is potentially quite complicated-- something like:
{ foo: [ { bar: 'baz', lol: [ { 'omg': ... etc
I built a directive which takes this data and drills down into it, dynamically rendering form fields for each object... I've got the data displaying perfectly, however the piece of the puzzle that's missing is, how can I take advantage of Angular's binding so that changing the value on the form input will actually update that attribute in the model?
Originally I was thinking this should be simple, as my code drills through the data structure, it can just be maintaining a path, so I'd end up with something like: 'myObject.foo.bar'
Then I could just pass that to the form input's ng-model attribute...... however, I could not get angular to recognize ng-model="path" where $scope.path = "myObject.foo.bar"... ng-model="{{path}}" did not work either.
My directive is using angular.forEach to drill down into this datastructure, and someone had mentioned to me that I should perhaps be using ng-repeat instead, but I wasn't sure if this is the correct way to go or not? I still feel like there should just be a way to do ng-model="path" and have that work...
Any guidance would be greatly appreciated.
To use dynamic property names, use array notation. I.e. myObject["foo"]["bar"]. Plunkr: http://plnkr.co/edit/W60F75?p=preview
Can you try setting an property on the scope with the value of the object itself and then refer it in the form element? Like below:
// In your script
$scope.obj = myObject;
// In your form
<input ng-model="obj.foo.bar" type="text" />