Is it possible to dynamically add an ng-repeat attribute to an element?
If so, how?
EDIT:
I was trying to create a component that will use a custom template inside it for each items on its list.
Example
<custom-component>
<item-template>
<span>{{item.name}}</span>
<item-template>
<custom-component>
Then the result shall be
<custom-component>
<ul>
<li ng-repeat="item in $ctrl.items">(the template)</li>
</ul>
</custom-component>
So I tried to just set the innerHTML of the ul to a string like so:
ul.innerHtml = "<li ng-repeat="item in $ctrl.items">{{item.name}}</li>"
A solution would be showing an element which have ng-repeat depending on a condition that you can change dynamically:
<div ng-switch="dynamicCondition">
<div ng-switch-when="true" ng-repeat="item in items">Element which have ng-repeat</div>
<div ng-switch-when="false">Element without ng-repeat</div>
</div>
Related
I'm developing a project using Angular 8.3.
I have a loop (using *ngFor) and I need that every div that I add has an unique reference name created dinamically).
This is my example code:
<div *ngFor="let item of list; let i = index;">
<div
cdkDropList
#done0="cdkDropList"></div>
</div>
Below I have another drag and drop zone that must receive these elements:
<div
cdkDropList
#donesList="cdkDropList"
[cdkDropListData]="DonesList"
[cdkDropListConnectedTo]="[done0, done1]"
class="movie-list"
(cdkDropListDropped)="onDrop($event)">
<div *ngFor="let itemList of DonesList" cdkDrag>{{itemList}}</div>
</div>
I need to change dynamically #done0, e.g. (#done0, #done1, #done2, #done3, etc).
How can I do it? I have tryed using #done{{i}}} but it doesn't work.
I don't know if I can use trackBy in this case and how to apply it.
Many thanks,
Reference a container:
<div *ngFor="let item of list; let i = index;" #doneContainer>
<div cdkDropList></div>
</div>
and in .ts you have different references in a NodeList:
const list = this.doneContainer.childNodes
or in a more Angular way, which is better, as it will update when necessary:
#ViewChildren('doneContainer') list: QueryList<any>;
I'm using ng-repeat on my page. ng-class working very well.
<div class="card news" ng-repeat="item in news track by $index" id="{{news.nid}}" ng-init="parentIndex = $index" ng-class="{hidden: '{{getCheck($index)}}' == 'true'}">
...
</div>
Now I need, if all items are hidden, show this div:
<h3 class="news-empty">No news</h3>
Whats the rules? How can I do it? Thanks.
You need another method that checks if all elements are hidden:
$scope.everythingIsHidden = function() {
return $scope.news.every((new, index) => $scope.getCheck(index));
}
$scope.getCheck = function(index) { // Your getChek function that I suppose it checks if an element is hidden based on index
//...
}
<h3 class="news-empty" ng-if="everythingIsHidden()">No news</h3>
TheCog's answer will work. If you want to do this in a more 'Angular' way you're going to need to refactor what you have.
You shouldn't be trying to hide them with a CSS class. ngRepeats have a built in filter syntax. So, you should be filtering them out.
<div class="card news"
ng-repeat="item in news | filterMethod as results track by $index"
id="{{news.nid}}"
ng-init="parentIndex = $index"
>
<h3 class="news-empty" ng-if="results.length === 0" >No news</h3>
The as results statement in the repeat will store the filtered array in results. filterMethodneeds to be an angular filter and it will probably work similarly to your getCheck($index) method.
You want to add an ngShow to the h3 tag, and aim it at a function you write in your controller that checks if the array is empty, probably by iterating over the same array that's hidden and running getCheck($index) on each.
I have this markup:
<div data-bind="foreach: package() ? package().Products() : []">
<ul data-bind="foreach: Items">
<li>
<div>
<img data-bind="attr: { src: ImageUrl, alt: 'ItemId_' + ItemId }">
</div>
</li>
</ul>
</div>
What I want to achieve (in the markup if possible) is to display only distinct items based on the ItemId, so if there are multiple items with the same ItemId I'll display only one of them.
Is it possible to do that in the markup data-bind property?
There is no straightforward way to filter for unique items in the HTML, and it isn't in keeping with good Knockout programming to put program logic into the HTML. Make a computed that collects the unique items and iterate over the computed.
I am having issue with $index in angular.I have a ng-repeat inside which I am using $index to keep track of unique class.
Here is my code:
<div ng-repeat="style in styleArr">
<div class="myclass{{ $index }}">
</div>
</div>
In angular controller I am appending a div inside myclass0,But not working.
Here is my controller.
myClass = angular.element('.myclass0');
myClass.append('<div class="test">Hello World..<test>');
When I try to do this:
<div ng-repeat="style in styleArr">
<div class="myclass0">
</div>
</div>
Its working fine.Any suggestion?
I think you want a unique classes for each div for applying a unique CSS. You can implement it by assigning a unique class or assigning a unique Id. For a Class, you need to use "ng-class" directive.
<div ng-repeat="style in styleArr">
<div ng-class="myclass{{ $index }}">
</div>
</div>
For a unique Id use :
<div ng-repeat="style in styleArr">
<div id="style{{ $index }}">
</div>
</div>
Best option is to use unique Id for performing a operation. If you want to assign only a styles then use Unique classes.
Use ng-class, it allows for expressions in the class name
<div ng-repeat="style in styleArr">
<div ng-class="myclass{{ $index }}">
</div>
</div>
More info on ng-class: https://docs.angularjs.org/api/ng/directive/ngClass
Use "ng-class" instead of "class"
<div ng-repeat="style in styleArr">
<div ng-class="myclass{{ $index }}">
</div>
</div>
you have to change class for ng-class
You can't do it reliably the what you are trying to do it. You need to understand how digest cycle and compilation/rendering of templates in Angular works. Then you would understand that element with class myclass0, myclass1, etc. - are not available at the time yo are trying to fetch them from DOM. Again - this is the reason why you should never do any DOM manipulations in controllers.
You should either use custom directive i your case or existing Angular directives like ngIf/ngShow, etc.
For example:
<div ng-repeat="style in styleArr">
<div class="myclass" ng-if="style.show">
<div>Hello ...</div>
</div>
</div>
and in controller
// show "Hello" in the first myclass
$scope.styles[0].show = true;
My advice would be not to have DOM manipulation inside controllers. That is what directive is used for. However in your case if you just want to append a div for the first iteration you can do something like this:
<div ng-repeat="style in styleArr">
<div ng-show="$first" class="test">Hello World..</div>
</div>
More on ng-repeat and $first
If I have a ng-repeat directive bind with my initial data,
<!-- list 1-->
<li ng-repeat="data in datas">{{data.name}}</li>
and I change the data by another ng-repeat and ng-model directive,
<!-- list 2-->
<li ng-repeat="data in datas">
<input type="text" ng-model="data.name">
</li>
In Angular way, any method can do list 1 ng-repeat data refresh not immediately (after I click a Save button)?
<button ng-click="save()">Save</button>
You can use a second (temporary) clone to make the changes and copy the changes over to the actual object using angular.copy.
The actual list:
<ul><li ng-repeat="item in items">
{{item.name}} (id: {{item.id}})
</li></ul>
Edit the list:
<ul><li ng-repeat="item in tempCopy">
<input type="text" ng-model="item.name" />
</li></ul>
<button ng-click="persistChanges()">Save</button>
<button ng-click="discardChanges()">Discard</button
In your controller:
/* Persist the changes */
$scope.persistChanges = function () {
angular.copy($scope.model.tempCopy, $scope.model.items);
};
/* Discard the changes */
$scope.discardChanges = function () {
angular.copy($scope.model.items, $scope.model.tempCopy);
};
See, also, this short demo.
Finally, there is a similar example on the Angular docs on angular.copy.
It seems you are creating new items within datas by extending the array by one element? If this is so, why not use a different model for the form and push the result onto the array data when the save button is clicked?
Similarly, when editing an item, clone the array element and make it the model for the resulting form, then modify the original array element when the save button is clicked.