I'm trying out Angular custom filter example from: https://scotch.io/tutorials/building-custom-angularjs-filters#filters-that-actually-filter which in my version looks like:
<!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="demo" >
<div>
<p><strong>Original:</strong></p>
<ul class="list">
<li ng-repeat="x in example1">{{ x.name }}</li>
</ul>
<p><strong>Static Language Filter:</strong></p>
<ul class="list">
<li ng-repeat="x in example1 | staticLanguage">{{x.name }}</li>
</ul>
</div>
</div>
<script>
var app = angular.module('myApp', []);
var counter=0;
app.controller('demo', function($scope){
$scope.example1 = [
{name: 'C#', type : 'static'},
{name: 'PHP', type : 'dynamic'},
{name: 'Go', type : 'static'},
{name: 'JavaScript', type: 'dynamic'},
{name: 'Rust', type: 'static'}
];
});
// Setup the filter
app.filter('staticLanguage', function() { // Create the return function and set the required parameter name to **input**
return function(input) {
counter+=1;
console.log(counter);
var out = [];
// Using the angular.forEach method, go through the array of data and perform the operation of figuring out if the language is statically or dynamically typed.
angular.forEach(input, function(input) {
if (input.type === 'static') {
out.push(input);
}
});
return out;
};
});
</script>
</body>
</html>
It seems from console.log that for some reason custom filter function staticLanguage is called two times but from the code itself it is called only one time: ng-repeat="x in example1 | staticLanguage"
Anyone has any idea why?
P.S I've yet to figure out what does "dirty-checking" has to do with my question...
if I remove counter variable and just put some console.log("text") in it's place staticLanguage function is still called two times
As far as I am aware this is due to AngularJS dirty-checking and has been asnwered elsewhere here. This is normal, have a read of the link.
This is normal, angularjs uses a 'dirty-check' approach, so it needs to call all the filters to see if any changes exist. After this it detects that you have a change on one variable (the one that you typed) and then it re-executes all filters again to detect if it has other changes.
See the first answer of this question
How does data binding work in AngularJS?
Well, I don't know if this will serve to you , but here's a snippet working that could be a possible solution for you:
var app = angular.module('app', []);
app.controller('mainCtrl', function($scope) {
$scope.languages = [
{
"name":"C#",
"type":"static"
},
{
"name":"PHP",
"type":"dynamic"
},
{
"name":"Go",
"type":"static"
},
{
"name":"JavaScript",
"type":"dynamic"
},
{
"name":"Rust",
"type":"static"
}
];
$scope.static_languages = $scope.languages.filter(x => x.type == 'static');
$scope.dynamic_languages = $scope.languages.filter(x => x.type == 'dynamic');
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js">
</script>
</head>
<body ng-controller="mainCtrl">
<div>
<p><strong>All languages:</strong></p>
<ul class="list">
<li ng-bind="language.name" ng-repeat="language in languages"></li>
</ul>
<p><strong>Static Languages Filter:</strong></p>
<ul class="list">
<li ng-bind="language.name" ng-repeat="language in static_languages"></li>
</ul>
<p><strong>Dynamic Languages Filter:</strong></p>
<ul class="list">
<li ng-bind="language.name" ng-repeat="language in dynamic_languages"></li>
</ul>
</div>
</body>
</html>
Related
I'm trying to access an object in JSON with AngularJS, and display the values. I have done this when I create an array in JSON but this time I want to show an example with an object. This is my code:
My JSON File
{ "user": {
"Name":"Ben",
"City":"New York"}}
My angular app
var app = angular.module('myApp', []);
app.controller('jsonObjectExample', function($scope, $http) {
$http.get("jsonobject.json").then(function (response) {
$scope.myData = response.data.user;
});
});
My HTML
<body>
<div ng-app="myApp" ng-controller="jsonObjectExample">
<ul>
<li ng-repeat="x in myData">
{{ x.Name + ', ' + x.City }}
</li>
</ul>
</div>
</body>
Here is a link to these files on plunker: https://plnkr.co/edit/uBRf99AjYH9zX0WuHsW3?p=preview
Can someone explain where I'm going wrong? Thanks.
remove the ng-repeat. myData is object, not an array so no need to use the ng-repeat
<body>
<div ng-app="myApp" ng-controller="jsonObjectExample">
<ul>
<li >
{{ myData.Name + ', ' + myData.City }}
</li>
</ul>
</div>
</body>
Demo
If you are using ng-repeat make sure the json which you are parsing should give some array value.
you can correct your json like:
{ "user": [{
"Name":"Ben",
"City":"New York"}]}
Other codes are working fine. Please check this
I made the below code to learn Angular. It uses the input entered by user to make an ajax request for a json file that contains a list of object, then print that list to the user.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script type="text/javascript">
angular.module('myApp', [])
.controller('myController', function($http) {
var ctlr = this;
ctlr.param = "";
ctlr.responses = [];
this.makeQuery = function() {
$http.get('http://localhost:8080?p=' + ctlr.param))
.then(function(data) {
ctlr.response = data; // data -> [{key1: value1,...},...]
});
};
});
</script>
</head>
<body ng-app="myApp">
<div ng-controller="myController as mc">
<input type="text" ng-model="mc.param">
<input type="submit" ng-click="mc.makeQuery()" value="Submit">
<ul>
<li ng-repeat="res in responses">
<span>{{res.key1}}, {{res.key2}}</span>
</li>
</ul>
</div>
</body>
</html>
When I run this code in Chrome, I see a list of empty bullet points. Chrome DevTools shows the json file returned as expected so I know ctlr.param works. However the list has empty bullet points so ng-repeat does not work correctly. It seems I cannot access cltr.responses properly. Does anyone know why?
Your responses object is binded to this and not to $scope as you are using controller as
You should use mc.responses instead of responses
<li ng-repeat="res in mc.responses">
<span>{{res.key1}}, {{res.key2}}</span>
</li>
You can read more from johnpapa style
Above solution is right but as i checked the complete code and found that there is one mistake.
In script code
ctlr.response = data; // data -> [{key1: value1,...},...] should be
ctlr.responses = data; // data -> [{key1: value1,...},...]
I've got a function in my controller very easy that just stamp a console.log. I need to conditioning a button using a function but inside the ng-repeat the controller repeats everything many times! Is it normal? Is it possible avoid this? Thanks. An example here http://plnkr.co/edit/sME67gQEZQSLI9FOwEAG?p=preview
relative code:
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.4.5" data-semver="1.4.5" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="DigestApp">
<div ng-controller="UserCtrl as uc">
<h1>Please open the console to see</h1>
<ul>
<li ng-repeat="user in uc.users" ng-class="uc.userClasses(user)">
{{user.name}}
<button ng-if="uc.isUserEnabled(user)"
ng-click="uc.disableUser(user)">Disable</button>
</li>
</ul>
</div>
</body>
</html>
javascript:
angular.module("DigestApp", [])
.controller('UserCtrl', function(User) {
var vm = this;
vm.users = User.list();
vm.isUserEnabled = function(user) {
console.log('isUserEnabled');
return user.active;
};
vm.userClasses = function(user) {
console.log('userClasses');
return []
.concat(user.active ? ['user-active'] : [])
.concat(user.loggedIn ? ['user-logged-in'] : [])
.concat(user.isMe ? ['user-is-me'] : [])
.join(' ');
};
vm.disableUser = function(user) {
user.active = false;
};
})
.factory('User', function() {
return {
list: function() {
return [{
name: "me",
active: true,
loggedIn: true,
isMe: true
}];
}
};
});
Yes, this is normal. There is no way that angular can tell whether the result of the function will have changed, so it calls it on every digest loop. If you want to avoid that you should calculate the value once and set the result as an attribute on the user object.
<li ng-repeat="user in uc.users" ng-class="user.classes">
{{user.name}}
<button ng-if="user.active"
ng-click="uc.disableUser(user)">Disable</button>
</li>
and in the controller add some code to precalculate a user.classes attribute on each user object (and to update it when you change the state of the model).
Please update your li in the HTML to the below. I got it working here http://plnkr.co/edit/Cx5OZaY0dhmBT4WLYZpX?p=info.
<li ng-repeat="user in uc.users" ng-class="{ 'user-active': user.active, 'user-logged-in': user.loggedin, 'user-is-me': user.isme }">
{{user.name}}
<button ng-if="user.active" ng-click="uc.disableUser(user)">Disable</button>
</li>
By using a function in your ng-class and ng-if it was evaluating to often. You can just pass the scope variables instead.
Pretty new to Angular, and I'm trying to do a sort of unconventional operation.
Say I have an array like this: ["A","B","C","D","E","F","G"];
I want to output HTML like this:
<ul>
<li>A</li>
<ul>
<li>B</li>
<ul>
<li>C</li>
<ul>
<li>D</li>
<ul>
<li>E</li>
<ul>
<li>F</li>
<ul>
<li>G</li>
</ul>
</ul>
</ul>
</ul>
</ul>
</ul>
</ul>
Essentially, I just want to keep nesting until I hit the end of the array. I'm having trouble figuring out how to do this. I don't have any code examples, unfortunately, because I'm having trouble how to do this without freezing the browser inside a while loop.
Nevertheless, here's what I've got:
<div class="trail" ng-include="'trail'"></div>
<script type="text/ng-template" id="trail">
<li>{{trailItem.content}}<li>
<ul ng-repeat="trailItem in post.trail" ng-include="'trail'">
</ul>
</script>
The above is meant to work with a data structure where post is an array of objects, of which content is a property.
However, this loops forever, and the browser freezes.
var ary = ["A", "B", "C", "D", "E", "F", "G"];
var $container = $('<div></div>');
var dom = $container;
for (var i = 0; i < ary.length; i++) {
dom = appendDom(dom, ary[i]);
}
function appendDom(dom, value) {
var $ul = $('<ul><li>' + value + '</li></ul>');
$(dom).append($ul);
return $ul;
}
alert($container.html());
The output is your need
I couldn't get it to work exactly with the one dimensional array like you posted but I did find a really good example with a jsfiddle at http://benfoster.io/blog/angularjs-recursive-templates
Also, here is what I have so far:
http://jsfiddle.net/haydenk/s19v2f1m/3/
<div ng-controller="MainCtrl">
<script type="text/ng-template" id="awesomeTree">
{{ awesomeThing }}
<ul ng-if="awesomeThings">
<li ng-repeat="awesomeThing in awesomeThings" ng-include="'awesomeTree'"></li>
</ul>
</script>
<ul>
<li ng-repeat="awesomeThing in awesomeThings" ng-include="'awesomeTree'"></li>
</ul>
</div>
var app = angular.module('testApp',['ngAnimate']);
app.controller('MainCtrl', function ($scope) {
$scope.awesomeThings = ['A','B','C','D','E','F','G','H'];
});
try this one .
HTML :
<div ng-controller="testCtrl">
<div add-ul-li arr-list-val=arrList>
</div>
</div>
JS :
app.controller("testCtrl",function($scope){
$scope.arrList = ["A","B","C","D","E","F","G"];
})
.directive("addUlLi",function(){
var finalHtml="";
return {
scope : {arrListVal: '='},
link: function(scope,ele,attr){
scope.arrListVal.reverse();
angular.forEach(scope.arrListVal,function(oneElement,key){
console.log(key)
if(key==0){
finalHtml = "<ul> <li>"+oneElement+"</li> </ul>";
}else{
finalHtml = "<ul> <li>"+oneElement+" "+finalHtml+"</li> </ul>";
}
if((key+1)==scope.arrListVal.length){
ele.append(finalHtml);
}
})
}
}
})
Check this plunker
My template is loading but I get an error that the controller is undefined. The controller does exist in my sources exactly at the location defined. What is wrong with this code?
Error: [ng:areq] http://errors.angularjs.org/1.2.14/ng/areq?p0=ItemsController&p1=not%20aNaNunction%2C%20got%20undefined
at Error (native)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js:6:450
at xb
This is my html:
<div ng-app="myApp">
<ul ng-controller="ItemsController" class="nav">
<input type="text" value="ItemName" ng-model="newItemName" placeholder="name of new item...">
<button ng-click="addItem()">Add Me</button>
<li ng-repeat="item in items.data" id="item{{item.id}}">
{{item.title}}
<a ng-click="deleteItem($index)" class="fa fa-trash-o"></a>
</li>
</ul>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular-route.js"></script>
<script type="text/javascript" src="js/te.js"></script>
'use strict';
var myApp = angular.module("myApp", []);
myApp.factory("items ", function() {
var items = {};
items.data = [];
return items;
});
myApp.controller("ItemsController", function ItemsController($scope, items) {
$scope.items = items;
$scope.deleteItem = function(index) {
items.data.splice(index, 1);
}
$scope.addItem = function(index) {
items.data.push({
id: $scope.items.data.length + 1,
title: $scope.newItemName
});
}
});
The Only Problem I see in your code is in following line:
myApp.factory("items ", function() {
space in the factory name "items " and you are injecting in your controller as items.
Here is the working PLNKR of your code, proof its working fine.
Happy Helping!
I have faced this problem many a times and usually this is caused when you have not included your js in the template.
If its not the case, then if you could share your some part of code, then only anybody will be able to answer it properly.