I'm trying to setup a nested repeat in angular using an associative array of arrays. For example I have a structure as such:
collections['key1'] = [obj1,obj2,obj3,obj4];
collections['key2'] = [obj5,obj6,obj7];
I want to have a view with a structure of:
<div ng-repeat="collection in collections">
<h4>{{collection.id}}</h4>
<div ng-repeat="item in collection">
<span>{{item.name | item.value}}</span>
</div>
</div>
However as soon as I add in ng-repeat="collection in collections" my view becomes blank. Is there a way to do this in angular or will I need to update the way i'm storing my data if I want to loop it in such a way? Thanks.
Just to give you an example how to use it
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.school = {
classes:[
{name:"Class 1", peoples:["Peter","Sue","Marc"]},
{name:"Class 2", peoples:["John","Edward","Sara"]}
]
}
});
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="class in school.classes">
<h4>{{class.name}}</h4>
<div ng-repeat="person in class.peoples">
<label>{{person}}</label>
</div>
<br>
</div>
</div>
</body>
</html>
Related
Is there any way to get innerHTML code of rendered element that includes ng-repeat loop?
For example:
<div id="container">
<div ng-repeat="e in ctrl.elements>{{e.name}}</div>
</div>
You can use $document[0].getElementById("container").innerHTML. Remember to call it after ng-repeat's job is done - I've delayed it in snippet below.
angular.module('app', [])
.controller('ExampleController', function($scope, $document, $timeout) {
$scope.ctrlelements = [{name: "aaaa"}, {name: "bbbb"}];
console.log($document[0].getElementById("container").innerHTML)
$timeout(function(){
console.log($document[0].getElementById("container").innerHTML)
}, 1000)
});
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<body ng-app="app">
<div ng-controller="ExampleController">
<div id="container">
<p ng-repeat="e in ctrlelements track by $index">{{e.name}}</p>
</div>
</div>
</body>
PS. There may be some better way to solve your problem than dealing with innerHTML
I am new in angular js, I am trying to format a json data with angular js.
Here is my json data
[
{"field_add_link": "Home"},
{"field_add_link": "About Us"}
]
here is my conroller
var myApp = angular.module('myApp', ['ngSanitize']);
myApp.controller('myController',function($scope, $http) {
$http.get('http://localhost/drupal3/menu')
.then(function(response) {
$scope.links = response;
});
});
and finally here is how i am fetching the json data with angular
<div class="col-md-8 content" ng-controller ="myController">
<div class="col-md-12" ng-repeat="link in links" ng-bind-html="links">
<p>{{ link.field_add_link }}</p>
</div>
</div>
no output was shown after this, giving an error Error: [$sce:unsafe] Attempting to use an unsafe value in a safe context. in the browser's console
but when I used ng-bind-html="links[0].field_add_link instead of ng-bind-html="links" and <p>{{ link[0].field_add_link }}</p> instead of <p>{{ link.field_add_link }}</p>
then i get Home as output 'without interpreting the tag'
Pls, how do I go about this?
First of all you dont need the ng-bind-html attribute on your div with ng-repeat. It should be on your p tag. Second, you need to bind link (the current element of the ng-repeat-loop) not links (the array). Although you need to look into the error [$sce:unsafe]. HTMl can only be bind to an element-body if it is trusted. For that you need to have, for example, a filter.
myApp.filter ('to_trusted', ['$sce', function ($sce) {
return function (text) {
return $sce.trustAsHtml (text);
};
}]);
<div class="col-md-8 content" ng-controller ="myController">
<div class="col-md-12" ng-repeat="link in links">
<p ng-bind-html="link.field_add_link | to_trusted"></p>
</div>
</div>
You just need to move your ng-bind-html from div to <p> like following code.
<p ng-bind-html="link.field_add_link"></p>
var myApp = angular.module('myApp', ['ngSanitize']);
myApp.controller('myController', function($scope, $http) {
var data = [{"field_add_link": "Home"},
{"field_add_link": "About Us"}];
$scope.links = data;
//For demo, removed the http call
});
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-sanitize.js"></script>
</head>
<body ng-app="myApp">
<div class="col-md-8 content" ng-controller="myController">
<div class="col-md-12" ng-repeat="link in links">
<p ng-bind-html="link.field_add_link"></p>
</div>
</div>
</body>
I have list of items in ng-repeat
<div layout="column"
class="md-whiteframe-1dp"
ng-repeat="item in child.items track by item._id"
id={{item._id}}child>
</div>
I want to append one more DOM element(one more itemToAppend) into list whithout touching child.items scope. I want just append the same look DOM element but with new data.
itemToAppend = {name: "itemToAppend", _id: "111"}
how to do it?
thanks in advance!:)
You just need to take another scope variable with empty array type and push the value on button click. Here I just have taken an text input and button for reference. But you can use the same in your way. Below is the code sample:
HTML:
<head>
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-app="sampleApp">
<div ng-controller="myController">
<input ng-model="newItem" type="text" />
<button ng-click="add(newItem)">Add</button>
<div ng-repeat="arr in child">
{{arr}}
</div>
<div ng-repeat="arr in tempchild track by $index">
{{arr}}
</div>
</div>
</div>
</body>
</html>
JS:
(function(angular){
var module = angular.module("sampleApp",[])
.controller("myController", ["$scope", function($scope){
$scope.child = ['A', 'B' , 'C', 'D'];
$scope.tempchild = [];
$scope.add = function(item) {
$scope.tempchild.push(item);
};
}]);
})(window.angular);
As you can see in above code, you will need to take another ng-repeat which iterates with the new $scope variable.
Full example can be found Here
I added a button which will help users to add items.
<input ng-model="newItem" type="text"></input>
<button ng-click="add(newItem)">Add</button>
$scope.itemsInFolder = ["A", "B", "C", "D"];
var newItemsToAdd= $scope.itemsInFolder;
$scope.add = function(item) {
newItemsToAdd.push(item);
};
Bind newItemsToAdd with ng-repeat
I am new to angular. I have a task to display json data in specific design, but I have not idea about nesting of json. Is it possible to check if the data is json or an array of json and then display the output.
Here I am trying to display data only if it is an array. But it is not working. Kindly help.
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp">
<div ng-controller="readJson as rj">
<div ng-repeat="d in rj.data">
<ul>
<div ng-model="myVar" ng-init="myVar = "{{isArray(d.third)}}>
<div ng-if="myVar">
<li>{{d.third}}</li>
</div>
</ul>
</div>
</div>
</div>
</body>
<script>
(function(){
var app=angular.module('myApp',[]);
app.controller('readJson',function($scope){
$scope.isArray = angular.isArray;
this.data=[{"first":"one","second":"two","third":"three"},
{"first":"ONE","second":"two","third":"three"},
{"first":"onE","second":"two","third":
[
{"first":"1one","second":"2two","third":"3three"},
{"first":"1ONE","second":"2two","third":"3three"}
]}];
});
})();
</script>
</html>
Here you go. This example will display data only when "third" param is an array.
https://plnkr.co/edit/EX0BvcYrLPFbiN2ezlqQ
<div ng-repeat="d in data">
<ul>
<div ng-init="myVar = isArray(d.third)"></div>
<div ng-if="myVar">
<li>{{d.third}}</li>
</div>
</ul>
</div>
The problem was in ng-init="myVar = "{{isArray(d.third)}} - you need to make sure isArray(d.third) is in expression (between "") and there is no need to use {{}} syntax within ng-init directive. It will evaluate expression for you (check an example).
I currently have this site - http://dev.5874.co.uk/scd-data/ where I have a dropdown which displays results from WP-API which I am pulling in through AngularJS.
It currently combines the two sets of results as they're separate URL's, the results are in categories within a custom post type so if both posts are 'tagged' in the same category chosen they display twice. I need a way to combine the two sets of results but only showing one of the posts - I hope this makes sense. I'm very new to API data and AngularJS and I imagine there is a much simpler way of doing this. Any help would be much appreciated. Here is a snippet of my code to show how it's currently working.
Thanks in advance!
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<style>
.desc {display: none;}
</style>
<script type="text/javascript">
$(function(){
$('.selectOption').change(function(){
var selected = $(this).find(':selected').text();
//alert(selected);
$(".desc").hide();
$('#' + selected).show();
}).change()
});
</script>
<script>
var app = angular.module('myApp', []);
app.controller('northWestCtrl', function($scope, $http) {
var url = 'http://scd.blaze.wpengine.com/wp-json/posts?type=listings&filter[listing_area]=northwest';
$http.get(url).then(function(data) {
$scope.data = data.data;
});
});
</script>
<select class="selectOption">
<option>Search by Region</option>
<option>NorthWest</option>
<option>NorthEast</option>
<option>Midlands</option>
<option>EastAnglia</option>
<option>SouthEast</option>
<option>SouthWest</option>
<option>Scotland</option>
<option>Wales</option>
<option>NorthernIreland</option>
<option>ChannelIslands</option>
</select>
<div id="changingArea">
<body ng-app="myApp">
<div id="NorthWest" class="desc">
<div ng-controller="northWestCtrl">
<div ng-repeat="d in data">
<h2 class="entry-title title-post">{{d.title}}</h2>
<img src="{{d.acf.logo}}">
<div id="listing-contact">Contact: {{d.acf.contact}}, {{d.acf.position}}</div>
<div id="listing-address-1">
{{d.acf.address_1}}, {{d.acf.address_2}} {{d.acf.address_3}} {{d.acf.town}} {{d.acf.county}} {{d.acf.postcode}}
</div>
<div id="listing-phone">Telephone: {{d.acf.telephone}}</div>
<div id="listing-mobile">Mobile: {{d.acf.mobile}}</div>
<div id="listing-email">Email: {{d.acf.email}}</div>
<div id="listing-website">Website: {{d.acf.website}}</div>
<div id="listing-established">Established: {{d.acf.established}}</div>
<div id="listing-about">About: {{d.acf.about}}</div>
<div id="listing-mailingaddress">Mailing Address: {{d.acf.mailing_address_}}, {{d.acf.mailing_address_2}}, {{d.acf.mailing_address_3}}, {{d.acf.mailing_town}}, {{d.acf.mailing_county}}, {{d.acf.mailing_postcode}}</div>
<div id="listing-directions">Directions: {{d.acf.directions}}</div>
<div id="scd-link">View on The Shooting Club Directory</div>
</div>
</div>
</div>
</body>
</div>
Here is a working code pen - http://codepen.io/anon/pen/yePYdq
Angular is a great JavaScript front-end framework to choose, and you're off to a good start, but a lot of changes could be made. I've made some suggested changes for easier ways to do things below.
See this CodePen for all changes.
It looks like you've grasped the idea of ng-repeat, but there's definitely a lot of repeated HTML and JS in your view and controller, so let's see if we can do better.
Let's try this without jQuery to avoid direct manipulation of the DOM. And instead of many controllers, we can do this with a single controller.
<div ng-app="MyApp">
<div ng-controller="MyController">
...
</div>
</div>
<script type="text/javascript">
var app = angular.module('MyApp', []);
app.controller('MyController', ...);
</script>
For the dropdown, we'll use ng-repeat in our view and display the names of the shooting types from our model
...
<select ng-model="selectedListing">
<option
ng-repeat="listingShootingType in listingShootingTypes"
value="{{listingShootingType.name}}">
{{listingShootingType.name}}
</option>
</select>
...
<script type="text/javascript">
...
// Our selections/filters
$scope.listingShootingTypes = [
'All',
'Air Rifle/Air Pistol',
'Clay',
'ABT',
'Double Trap',
'English Skeet',
'English Sporting',
'Fitasc',
'Olympic Skeet',
'Olympic Trap',
'Simulated Game',
'Sport Trap/Compact',
'Universal Trench',
'ZZ/Helice',
'Rifle',
'Centrefire Target Rifle',
'Gallery Rifle',
'Muzzle Loading',
'Practice Shotgun',
'Smallbore Rifle'
];
...
</script>
With only one controller, we can still use ng-repeat for each listing.
<div ng-repeat="d in data">
<h2 class="entry-title title-post">{{d.title}}</h2>
<div id="listing-image"><img src="{{d.acf.logo}}"></div>
<div id="listing-contact">Contact: {{d.acf.contact}}, {{d.acf.position}}</div>
<div id="listing-address-1">
{{d.acf.address_1}}, {{d.acf.address_2}} {{d.acf.address_3}} {{d.acf.town}} {{d.acf.county}} {{d.acf.postcode}}
</div>
<div id="listing-phone">Telephone: {{d.acf.telephone}}</div>
<div id="listing-mobile">Mobile: {{d.acf.mobile}}</div>
<div id="listing-email">Email: {{d.acf.email}}</div>
<div id="listing-website">Website: {{d.acf.website}}</div>
<div id="listing-established">Established: {{d.acf.established}}</div>
<div id="listing-about">About: {{d.acf.about}}</div>
<div id="listing-mailingaddress">Mailing Address: {{d.acf.mailing_address_}}, {{d.acf.mailing_address_2}}, {{d.acf.mailing_address_3}}, {{d.acf.mailing_town}}, {{d.acf.mailing_county}}, {{d.acf.mailing_postcode}}</div>
<div id="listing-directions">Directions: {{d.acf.directions}}</div>
<div id="scd-link">View on The Shooting Club Directory</div>
</div>
Finally... How do we only display listings that match our selected shooting type from the dropdown? We could use a custom Angular filter!
...
<div ng-repeat="d in data | filter:isSelectedListing">
...
<script type="text/javascript">
...
// Let's define a custom Angular filter because the WordPress JSON is complex
$scope.isSelectedListing = function(listing) {
// Show nothing if nothing is selected
if (angular.isUndefined($scope.selectedListing) || $scope.selectedListing == '') {
return false;
}
// Show all if 'All' is selected
if ($scope.selectedListing == 'All') {
return true;
}
// If the shooting type we're looking for is present, show the listing.
// To do this, we parse the WordPress JSON object model.
if (angular.isDefined(listing.terms.listing_shooting_type)) {
for (var i = 0; i < listing.terms.listing_shooting_type.length; i++) {
if (listing.terms.listing_shooting_type[i].name == $scope.selectedListing) {
return true;
}
}
}
return false;
};
...
</script>
Hopefully this gives you an idea of how we better leverage ng-repeat + DRY :)
The entire CodePen is here.