I'm trying to display a list inside a list. This loop works in JavaScript.
for ( i=0; self.InsuredCommoditiesList.length > i; i++){
self.CommoditiesCategories = self.InsuredCommoditiesList[i].Category;
for (j = 0; self.InsuredCommoditiesList[i].Items.length > j; j++) {
self.CommoditiesList = self.InsuredCommoditiesList[i].Items[j];
}
This is the body of my ng-repeat
<label ng-repeat="commo in QQCtrl.InsuredCommoditiesList track by $index">
{{commo.Category}}
<input type="checkbox"> {{commo.Items}}
</label>
And my result is almost correct, the problem is that "Items" are not being display individually. Instead it's just showing the whole array.
Example in the following picture:
Can I use something similar to position "j" in my ng-repeat to display the items individually?
The items in each list can be displayed using a list, for example: an unordered list (i.e. <ul>) or an ordered list (i.e. <ol>), with a list item (i.e. <li>) for each item in the array. In the example below, item is analogous to self.InsuredCommoditiesList[i].Items[j] in the for loop of the regular JavaScript example.
<ul>
<li ng-repeat="item in commo.Items">{{item}}</li>
</ul>
In fact, there is a repeat_expression1 where j could be used in a similar manner: (key, value) in expression, which would look like below:
<li ng-repeat="(j,item) in commo.Items">{{item}}</li>
A <label> is only permitted to only contain Phrasing content2 but the lists are Flow Content so move the ngRepeat up to another parent element like a <div> or a <span>. Then make the label, input and list tags child elements.
<div ng-repeat="commo in QQCtrl.InsuredCommoditiesList track by $index">
<label for="checkbox_{{$index}}">{{commo.Category}}</label>
<input type="checkbox" id="checkbox_{{$index}}">
<ul>
<li ng-repeat="item in commo.Items">{{item}}</li>
</ul>
</div>
See a demonstration of this below.
angular.module('QQapp', [])
.controller('ctrl', function($scope) {
this.InsuredCommoditiesList = [{
"id": 3,
"Category": "Agricultural liquids - Petroleum",
"Items": ["100% Produce", "Alcohol", "Appliances"]
},
{
"id": 4,
"Category": "Grocery Items (dry)",
"Items": ["Candy", "Canned goods", "Containers"]
},
{
"id": 6,
"Category": "Building materials",
"Items": ["Alfalfa", "All Non-perishable General Merchandise", "Almonds"]
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="QQapp" ng-controller="ctrl as QQCtrl">
<span ng-repeat="commo in QQCtrl.InsuredCommoditiesList track by $index">
<label for="checkbox_{{$index}}">{{commo.Category}}</label>
<input type="checkbox" id="checkbox_{{$index}}">
<ul>
<li ng-repeat="(j,item) in commo.Items" id="{{commo.id}}_{{j}}" >{{item}}</li>
</ul>
</span>
</div>
1 refer to the Arguments section of ngRepeat for supported formats
2https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label
You need to replace the inner loop of your equivalent javascript code in angularjs as well, i.e. you will need one more ng-repeat.
Something like:
<label ng-repeat="commo in QQCtrl.InsuredCommoditiesList track by $index">
{{commo.Category}}
<input type="checkbox" ng-repeat="item in commo.Items"> {{item}}
</label>
You have two loops in your JavaScript code, so you will need two loops in the angular to go through the inner list.
<label ng-repeat="commo in QQCtrl.InsuredCommoditiesList track by $index">
{{commo.Category}}
<input type="checkbox">
<label ng-repeat="item in commo.Items" >{{item}}</label>
</label>
Untested, but should work assuming commo.Items is a list of strings
You may try for this:
<label ng-repeat="commo in QQCtrl.InsuredCommoditiesList track by $index">
{{commo[0].Category}}
<input type="checkbox"> {{commo[0].Items}}
</label>
Related
I am trying to pass duplicate values in different formats but can not match parent and inner indexes hence I get Error: [ngRepeat:dupes]. that said, I pass object with multiple properties among which I have tags...see below
vm.hotels returns objects like below
0:object
tags:"tag1|tag2|tag3"
1:object
tags:"tag1|tag2|tag3"
vm.hTags is an array that matches each object like below
["tag1", "tag2", "tag3"]
within my controller I split tags and push then into an array within a loop which I pass to the view. this works as it should but I can not make it work with indexes within the view. below are nested ng-repeats
<li ng-repeat="item in vm.hotels track by $index">
<ul>
<li ng-repeat="tag in vm.hTags[$index]">
{{tag}}
</li>
</ul>
<li>
I tried to use vm.hTags[$parent.$index] but it does not work as duplicate error is thrown due to indexes. Perhaps I need to create some custom tracking property ?
The problem with nested ng-repeat is that is that if you use $index for both child and parent, it might conflict. In order to avoid it, we can use it by giving name. Like this
ng-repeat="(hotelIndex, item) in vm.hotels ..."
I don't know how you want to render it but here's a sample example of that:
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope) {
var vm = this;
vm.hotels = [{
tags: "tag1|tag2|tag3"
}, {
tags: "tag4|tag5|tag6"
}]
vm.hTags = [["tag1", "tag2", "tag3"], ["tag4", "tag5", "tag6"]]
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp" ng-controller="MainCtrl as vm">
<div ng-repeat="(hotelIndex, item) in vm.hotels track by hotelIndex">
<div ng-repeat="tag in vm.hTags[hotelIndex]">
{{tag}}
</div>
<br>
</div>
</body>
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope) {
var vm = this;
vm.hotels = [{
tags: "tag1|tag2|tag3"
}, {
tags: "tag4|tag5|tag6"
}]
vm.hTags = [["tag1", "tag2", "tag3"]];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular.min.js"></script>
<body ng-app="myApp" ng-controller="MainCtrl as vm">
<div ng-repeat="key in vm.hotels">
<div ng-repeat="tag in vm.hTags[$index]">
{{tag}}
</div>
</div>
<br>
<div ng-repeat="(key, value) in vm.hotels">
<div ng-repeat="tag in vm.hTags[key]">
{{tag}}
</div>
</div>
</body>
Please find the code change below,
<li ng-repeat="item in vm.hotels track by $index">
<ul>
<li ng-repeat="tag in vm.hTags[$index]">
{{tag}}
</li>
</ul>
<li>
Check and let me know.You made a syntax error
I have 2 directives: wa-hotspots & wa-tooltips.
On ng-mouseover of wa-hotspots it takes that $index of wa-hotspot and sets the visibility and position of wa-tooltip via ng-class:on and ng-style="tooltipCoords" by matching indexes.
Note: Since wa-hotspots & wa-tooltips share the same collection page.hotspots and therefore they share teh same index via ng-repeat
Problem:
When you hover over wa-hotspots it sets the ng-style position to ALL of the elements in wa-tooltips. I only want it ot set the proper matching index. Since the visiblity is controlled by ng-class, This doesn't really matter but it seems like it's extra overhead that could be avoid.
Therefore:
Question:
How can I make sure that my ng-style isn't styling all the wa-tooltips on hover of wa-hotspots? But rather, style only the tooltip that matches the proper shared index?
<ul id="wa-page-{{page.pageindex}}" class="wa-page-inner" ng-mouseleave="pageLeave()">
<li wa-hotspots
<map name="wa-page-hotspot-{{page.pageindex}}">
<area ng-repeat="hotspot in page.hotspots"
class="page-hotspot"
shape="{{hotspot.areashape}}"
coords="{{hotspot.coordinatetag_scaled}}"
ng-mouseover="showTooltip($index, hotspot.coordinatetag_scaled)"
ng-mouseout="hideTooltip()">
</map>
</li>
<li class="tooltip-wrapper">
<ul class="tooltip">
<li wa-tooltips
ng-repeat="hotspot in page.hotspots"
ng-class="{on: hovered.index == $index}"
ng-mouseover="hovered.active == true"
ng-mouseout="hovered.active == false"
ng-style="tooltipCoords" hotspot="hotspot">
</li>
</ul>
</li>
</ul>
tooltip:
You need to make it per item like in your case - hotspot.tooltipCoords then set that variable by index.
you can do the check inside the expression function.
Heres a fiddle
<div ng-controller="MyCtrl">
<div ng-repeat="item in items" ng-style="isChecked($index)">
name: {{item.name}}, {{item.title}}
<input type="checkbox" ng-model="item.checked" />
</div>
</div>
...
$scope.isChecked = function($index){
var color = $scope.items[$index].checked ? 'red' : 'blue';
return {color:color};
}
Instead of
ng-mouseover="hovered.active == true"
ng-mouseout="hovered.active == false"
use
ng-mouseover="hotspot.class== 'active'"
ng-mouseout="hotspot.class== ''"
and after that you can use hotspot.class in ng-class ie:
ng-class="hotspot.class"
Please see demo below:
var app = angular.module('app', []);
app.controller('homeCtrl', function($scope) {
$scope.items = [{
id: 1
}, {
id: 2
}, {
id: 3
}, {
id: 4
}]
});
.red {
background-color: yellow;
}
p {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="homeCtrl">
<p ng-repeat="i in items" ng-mouseover="i.class='red'" ng-class="i.class" ng-mouseout="i.class = ''">{{i.id}}</p>
</div>
</div>
Use the below one
<div class="col-md-4 col-xs-12 col-lg-4" ng-repeat="obj in items">
<button type="button" class="btn btn-sm pull-right" ng-class="obj.class" ng-click="obj.class='test'" >
Write a new class "test". Instead of click you can use the same in ngmouseover
I am trying to execute the below code where I'm trying use ng-repeat to iterate through a key:value pair.
But ng-repeat is not following the index instead of rendering the second key value its rendering the thrid index
HTML:
<div ng-app ng-controller="ItemsCtrl">
Type anything in the first box.
<div ng-repeat="(key, value) in item">
<input type="text" ng-model="item[key]" />
</div>
{{item | json}}
</div>
Javascript Controller:
function ItemsCtrl($scope) {
$scope.item = {
"1": "one",
"2": "two",
"10": "ten"};
}
Below is the jsfiddle link for the problem http://jsfiddle.net/nMjet/13/
Thanks #Blackhole.
Below the modified Code
HTML:
<div ng-app ng-controller="ItemsCtrl">
Type anything in the first box.
<div ng-repeat=" item in items">
<input type="text" ng-model="item[$indexxcdxdd]" />
</div>
{{item | json}}
</div>
Javascript Controller:
function ItemsCtrl($scope) {
$scope.items = ['one','two','ten'];
}
I'm getting started with Angular.js and I'm wondering how to do something along the lines of this (pseudocode):
<li ng-repeat="item in items">
<# if(item.dataType == "string") { #>
<input type="text" />
<# } else if(...) { #>
<input type="password" />
<# } #>
</li>
I know the above code is not angularish, and I know that for simple processing I could use a conditional ng-hide or ng-show or something similar. But for complex behavior, if I had to perform various data checks and business logic, how could I dynamically generate DOM elements with Angular.js?
Within the angular world, DOM manipulation is accomplished using angularjs directives. Here is the angular documentation on directives: https://docs.angularjs.org/guide/directive, you would do well to read through this.
Here is some sample code that will accomplish the idea of your psuedo code:
var myApp = angular.module('myApp', []);
myApp.controller('MyController', function ($scope){
$scope.items = [
42, "hello, world!", 3.14, "i'm alive!"
]
});
myApp.directive('myInputDirective', function () {
return {
restrict: 'E',
replace: true,
template: '<div></div>',
link: function (scope, element, attrs) {
if (typeof scope.current === "string") {
element.append('<input type="text">');
} else {
element.append('<input type="password">');
}
}
}
});
and here's how the html would look:
<div ng-controller="MyController">
<ul ng-repeat="item in items" ng-init="current = item">
<my-input-directive></my-input-directive>
</ul>
</div>
Here is a plnkr with the working example: http://plnkr.co/edit/iiS4G2Bsfwjsl6ThNrnS?p=preview
Directives are how the DOM is manipulated in angular. First thing to notice is that angular has a set of directives that come out of the box, we're using a few above (ng-repeat, ng-init, ng-controller). Above we've created a custom directive that will analyze the data type of each item in the items array of our MyController controller, and append the correct html element.
I imagine that you already understand the ng-repeat directive, so I'll skip that. I'll explain what I'm doing with the ng-init directive though. The ng-init directive allows you to evaluate an expression in the current scope. What this means is that we can write an expression that is evaluated in our current controllers scope, in this case the MyController scope. I am using this directive to create an alias for our current item named current. We can use this inside our directive to check what type the current item in the array iteration is.
Our directive myInputDirective, is returning an object with a few different properties. I won't explain them all here (I'll let you read the documentation), but I will explain what the link function is and what I am doing with it. A link function is typically how we modify the DOM. The link function takes in the current scope (in this case the scope of MyController), a jqLite wrapped element that is associated with the directive, and the attrs which is a hash object with key-value pairs of normalized attribute names and values. In our case, the important parameters are the scope, which contains our current variable, and the element, which we will append the correct input onto. In our link function, we're checking the typeof our current item from our items array, then we are appending an element onto our root element based on what the type of the current item is.
For this particular problem, what I'm doing above is overkill. But based off of your question I figured you were looking for a starting point for more advanced uses of angular apart from the built in directives that angular provides. These are somewhat advanced topics in angular, so I hope that what I've said make some sense. Check out the plunker and play around with it a bit, and go through some of the tutorials on https://docs.angularjs.org/guide. Hope this helps!
You can use ng-show to conditionally hide and show elements e.g.:
<input ng-show="item.dataType === 'string'" type="text"/>
<input ng-show="..." type="password"/>
Assuming your object looks like this:
$scope.items = [
{
dataType: 'string',
value: 'André Pena'
},
{
dataType: 'password',
value: '1234'
},
{
dataType: 'check',
value: true
}
];
Option #1 - ng-switch plunker
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="item in items">
<div ng-switch="item.dataType">
<div ng-switch-when="string" ><input type="text" ng-model="item.value" /></div>
<div ng-switch-when="password" ><input type="password" ng-model="item.value" /></div>
<div ng-switch-when="check" ><input type="checkbox" ng-model="item.value" /></div>
</div>
</li>
</ul>
</body>
Option #2 - ng-show plunker
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="item in items">
<div ng-show="item.dataType == 'string'" ><input type="text" ng-model="item.value" /></div>
<div ng-show="item.dataType == 'password'" ><input type="password" ng-model="item.value" /></div>
<div ng-show="item.dataType == 'check'" ><input type="checkbox" ng-model="item.value" /></div>
</li>
</ul>
</body>
Option #3 - ng-hide plunker
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="item in items">
<div ng-hide="!(item.dataType == 'string')" ><input type="text" ng-model="item.value" /></div>
<div ng-hide="!(item.dataType == 'password')" ><input type="password" ng-model="item.value" /></div>
<div ng-hide="!(item.dataType == 'check')" ><input type="checkbox" ng-model="item.value" /></div>
</li>
</ul>
</body>
You should use the ng-if directive.
<input ng-if="item.dataType === 'string'" type="text"/>
<input ng-if="..." type="password"/>
The problem with using ng-show like #rob suggested, is that it only uses CSS to hide the element, which is not ideal if you want the two inputs to have the same name/ID.
ng-if will remove the element from the DOM if the condition is not true.
for a problem this simple there's no need to go and implement your own directive.
I have a hash of objects, and the ID of this hash is binding to a RADIO BUTTON. When the user select this radio, I need to populate a select tag with options based on attribute of this model.
Its hard to explain, so I created a Codepen to show what I want:
http://codepen.io/rizidoro/pen/BeJjf
Thanks in advance!
Here's a codepen demo binding dynamically to a single SELECT element, with a working ng-model binding on selection change:
HTML:
<div ng-controller="TestCtrl">
<ul>
<li ng-repeat="attr in data">
<input type="radio" name='data-attr' value='{{attr.id}}' ng-model="selected.id" />{{attr.name}}
</li>
</ul>
<select ng-model="selected.value" ng-options="item.name for item in selectedAttr.values "></select>
</div>
JS:
function TestCtrl($scope) {
$scope.selected = {};
$scope.data = [
{"id":"113000",
"name":"Size",
"values":
[{"id":"92029","name":"Size A"},
{"id":"92030","name":"Size B"}]
},
{"id":"113002",
"name":"Color",
"values":
[{"id":"94029","name":"Blue"},
{"id":"94030","name":"Black"}]
}
];
$scope.$watch('selected.id', function(id){
delete $scope.selected.value;
angular.forEach($scope.data, function(attr){
if(attr.id === id){
$scope.selectedAttr = attr;
}
});
});
}
I have created a fiddle, that may solve ur problem. http://jsfiddle.net/qY2Zz/.
Seperated the data to a service.
animateAppModule.service('data', function(){...})
Assigned a model to the select box.
ng-model="$scope.selectedOption"
http://jsfiddle.net/wagedomain/afuz5/
I rewrote your HTML a little - not using ul / li tags where a div or span would suffice. Makes it easier.
Basically, inside the ng-repeat, you can do this:
<div ng-repeat="attr in data">
<input type='radio' name='data-attr' value='{{attr.id}}' />{{attr.name}}
<select ng-model="selected" ng-options="item.name for item in attr.values "></select>
</div>
It's the ng-options that makes this work. I also added a $scope.selected variable to model bind to but I'm not doing anything with it in the fiddle. Use as you need.