AngularJS - How to order ng-repeat using another array - javascript

Say I have an array of keys in a specific order
orderedNames=["mike","bob","sarah];
and I have a JSON that I want to show using ng-repeat but in the order that they appear in the array:
{"people":
{
"bob":{
"hair":"brown",
"eyes":"blue",
"height":"tall"
},
"sarah":{
"hair":"blonde",
"eyes":"blue",
"height":"short"
},
"mike":{
"hair":"red",
"eyes":"blue",
"height":"tall"
}
}
}
How do I write a filer that would cause ng-repeat to spit out the people in the order in which they are specified in the array?
<li ng-repeat="person in people | orderNames"></li>

You can define a custom filter.
Plunker: http://plnkr.co/edit/fiuuGoGZK7tM5oefKQlS
index.html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>Filter Example</title>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.2.x" src="http://code.angularjs.org/1.2.15/angular.js" data-semver="1.2.15"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<li ng-repeat="person in people|orderNames:orderedNames track by $index">{{person.hair}}</li>
</body>
</html>
app.js:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.people={
bob:{
hair:"brown",
eyes:"blue",
height:"tall"
},
sarah:{
hair:"blonde",
eyes:"blue",
height:"short"
},
mike:{
hair:"red",
eyes:"blue",
height:"tall"
}
};
$scope.orderedNames=["mike","bob","sarah"];
});
app.filter("orderNames",function(){
return function(input,sortBy) {
var ordered = [];
for (var key in sortBy) {
ordered.push(input[sortBy[key]]);
}
return ordered;
};
});

You could try something like this
<li ng-repeat="name in orderNames">
{{people[name]}}
</li>

use array as a reference :
http://jsbin.com/jujoj/14/edit
$scope.persons = {
bob:{
name:'bob'
},
mike:{
name: 'mike'
},
sarah: {
name: 'sarah'
}
};
$scope.orderedNames = [$scope.persons.mike, $scope.persons.bob, $scope.persons.sarah];
HTML : <ul ng-repeat="person in orderedNames">
<li>{{ person.name }}</li>
</ul>

to ng-repeat order by another array use
in the controller
$scope.somearray = [1,2,3,4] //or what ever you want to sort by
in the template.
| orderByArray:somearray:true/false
the true/false setting determines if stuff that isn't in the sortby array is outputted after the stuff that is or just dropped.
add the filter
var app = angular.module("app", []).filter("orderByArray", function () {
return function (input, sortBy, includeOrphans) {
//sorts by array and returns items with unsorted items at the end if they are not in the sortby array
if (!angular.isDefined(input)) { return; }
var ordered = [];
var remainder = _.cloneDeep(input);
angular.forEach(sortBy, function (sortitem) {
if (angular.isDefined(input[sortitem])) {
ordered.push(input[sortitem]);
delete (remainder[sortitem]);
}
});
if (includeOrphans) {
angular.forEach(remainder, function (remainingItem, key) {
ordered.push(input[key]);
});
}
return ordered;
};
});

Related

angular js filters working but with errors

Angular js filter Working Fine But Throwing Itteration Errors
var app = angular.module('NGapp', []);
app.filter('altDate', altDate);
app.controller('MainCtrl', MainCtrl)
function MainCtrl($scope) {
$scope.data = {
'listProductCost': [{
'data': 1
}, {
'data': 23
}, {
'data': 234
}, ]
}
}
function altDate(_) {
return function(value) {
console.log(value)
if (!value || value.length === 0) {
return [];
} else {
var f = []
angular.forEach(value, function(data) {
f.push(data['data']);
})
var s = []
s.push({
'min': _.min(f),
'max': _.max(f)
})
return s;
}
//return s;
};
}
app.factory('_', LodashFactory);
/** #ngInject */
function LodashFactory($window) {
return $window._;
}
<!DOCTYPE html>
<html ng-app="NGapp">
<head>
<meta charset="utf-8" />
<title>AngularJS </title>
<link rel="stylesheet" href="style.css" />
<script data-require="lodash.js#4.17.4" data-semver="4.17.4" src="https://cdn.jsdelivr.net/npm/lodash#4.17.4/lodash.min.js"></script>
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<md-card-content layout="row" layout-align="none" ng-repeat="datas in data.listProductCost | altDate ">
<div class="dark" flex="30">HO Cost</div>
<div>
<span>{{datas.min}}</span> % to <span>{{datas.max}}</span> %
</div>
</md-card-content>
</body>
</html>
Here is my Working Code With angularjs filter . the filter is working fine but iam getting itteration error in console
the purpose filter is to print only the minimum and maximum value of the discount. can anyone can resolve the issue or give me a idea to resolve this thanks in advance
I see you using lodash. Why not use _.minBy() instead of _.min() ?
That way you can reduce your altDate function to
altDate(_){
return function(value) {
return {
min: _.minBy(value, function(i) { return i.data }),
max: _.maxBy(value, function(i) { return i.data})
}
}
}

Angular Get Selected Value From Checkbox

I can't seem to get the selected item from an input checkbox.
<ul>
<li ng-repeat='shoe in shoebox'>
<input type='checkbox' ng-model='shoe.selected' id='shoe-{{shoe.name}}'>
<label for='shoe-{{shoe.name}}'>{{shoe.name}}</label>
</li>
<button ng-click='whatIsChecked(shoe.selected)'>Apply</button>
</ul>
Then in my controller:
$scope.whatIsChecked = function(selectedThing) {
console.log(selectedThing);
};
The above returns undefined.
The list items are displayed correctly, but the shoe.name or checked item doesn't seem to be stored by the ng-model.
the variable shoe is only valid in ng-repeat block.
If you want to got what is selected, you should try filter.
UPD:
Since you don't have the selected property, you should keep the selected items somewhere else by firing the ng-click event.
refer below code snippet.
angular.module("app", [])
.controller("myCtrl", function($scope) {
$scope.checkedShoes = [];
$scope.shoebox = [{
name: 'shoe1'
},
{
name: 'shoe2'
},
{
name: 'shoe3'
},
{
name: 'shoe4'
}
];
$scope.save = function(e, shoe) {
if (e.target.checked) {
$scope.checkedShoes.push(shoe);
} else {
var index = $scope.checkedShoes.indexOf(shoe);
if( index > -1) {
$scope.checkedShoes.splice(index, 1);
}
}
};
$scope.whatIsChecked = function() {
//var selected = $scope.shoebox.filter(function(item) {
// return item.selected === true;
//});
console.log($scope.checkedShoes);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="app" , ng-controller="myCtrl">
<ul>
<li ng-repeat='shoe in shoebox'>
<input type='checkbox' ng-click="save($event, shoe)" id='shoe-{{shoe.name}}'>
<label for='shoe-{{shoe.name}}'>{{shoe.name}}</label>
</li>
<button ng-click='whatIsChecked()'>Apply</button>
</ul>
</div>
You can get the checked items using a angular.Foreach it becomes easy when you have multiple items checked.
$scope.checkedItems = [];
angular.forEach($scope.shoebox, function(value, key) {
if (value.selected)
$scope.checkedItems.push(value.name);
});
Demo
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.shoebox = [{
name: 'Reboke',
selected: false
}, {
name: 'woodlands',
selected: false
}, {
name: 'Nike',
selected: false
}, {
name: 'Fila',
selected: false
}];
$scope.checkedItems = function() {
$scope.checkedItems = [];
angular.forEach($scope.shoebox, function(value, key) {
if (value.selected)
$scope.checkedItems.push(value.name);
});
}
});
<html>
<head>
<meta charset="utf-8" />
<title>AngularJS </title>
<link rel="stylesheet" href="style.css" />
<script src="https://code.angularjs.org/1.4.7/angular.js"></script>
</head>
<body ng-app="myApp" ng-controller="myCtrl">
<ul>
<li ng-repeat='shoe in shoebox'>
<input type='checkbox' ng-model='shoe.selected' id='shoe-{{shoe.name}}'>
<label for='shoe-{{shoe.name}}'>{{shoe.name}}</label>
</li>
<button ng-click='checkedItems()'>Apply</button>
Checked items are: {{checkedItems}}
</ul>
</body>
</html>

Angularjs - filter object by search value, but don't omit if the search value is in the second object

Having trouble even writing the subject with my lack of english.
So here I go, I have for example two objects connected by the colorid:
$scope.fruits = {{name:"apple",colorid:"1"},etc};
$scope.colors = {{id:"1",value:"red"};
I've built a nice table with search and filter, using ng-repeat
ng-repeat="fruit in fruits | orderBy:sortType:sortReverse | filter:search"
What I am trying to achieve is ... when i search/filter for "red", to still view "apple"..
Edit: Obviously there is no connection in the ng-repeat with the second object "colors", the simplest solution would be to iterate each "fruit" and .push its color value (red) in the "fruits" object itself, so when searched/filtered for "red", the "apple" object is still visible in the search table.
But I assumed there may be some "angular-ish" solution for connected tables and their relationship ids.
If I understood well you are trying to "connect" your arrays. So you can have nested ngRepeat, as below:
(function() {
"use strict";
angular
.module('app', [])
.controller('MainCtrl', MainCtrl);
MainCtrl.$inject = ['$scope'];
function MainCtrl($scope) {
$scope.fruits = [
{
"name":"apple",
"colorid":1
},
{
"name":"mango",
"colorid":2
},
{
"name":"papaya",
"colorid":3
}
];
$scope.colors = [
{
"id":"1",
"value":"red"
},
{
"id":2,
"value":"green"
},
{
"id":3,
"value":"yellow"
}
];
}
})();
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" />
</head>
<body ng-controller="MainCtrl">
<input type="text" class="form-control" ng-model="search" placeholder="Search...">
<ul ng-repeat="fruit in fruits track by $index">
<li ng-if="filtered.length" ng-bind="fruit.name"></li>
<ul>
<li ng-repeat="color in colors | filter: { id: fruit.colorid } | filter: search as filtered track by $index" ng-bind="color.value">
</li>
</ul>
</ul>
</body>
</html>

How do I trigger the manipulation of the DOM after a partial view is loaded in AngularJS?

How do I trigger the manipulation of the DOM after a partial view is loaded in AngularJS?
If I were using jQuery, I could do
$(document).ready(function(){
// do stuff here
}
But in Angular, in particular with partial views, how would I do such? As a more concrete example, I have the following basic non-interactive Angular app (html and js on the same page source):
http://cssquirrel.com/testcases/ang-demo/
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Angular Question</title>
</head>
<body data-ng-app="demoApp">
<div data-ng-view=""></div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script>
var app = angular.module('demoApp', []);
var controller = {
demoController: function ($scope, demoFactory) {
$scope.fruits = demoFactory.getFruits();
}
};
var factory = {
demoFactory: function () {
var fruits = ['apples', 'bananas', 'cherries'];
var factory = {
getFruits: function () {
return fruits;
}
};
return factory;
}
}
function appRoute($routeProvider) {
$routeProvider
.when('/step-1',
{
controller: 'demoController',
templateUrl: 'partial.html'
})
.otherwise({ redirectTo: '/step-1' });
};
app.config(appRoute);
app.factory(factory);
app.controller(controller);
</script>
</body>
</html>
Which has the following partial:
http://cssquirrel.com/testcases/ang-demo/partial.html
<ul>
<li data-ng-repeat="fruit in fruits">{{fruit}}</li>
</ul>
So, if in this basic app, I wanted to add a class "active" to the first list item in the list after the partial view has finished loading, how would I go about it?
You have to stop thinking in terms of DOM manipulation. It's not the first LI that's active, rather it's the first fruit that has been selected.
First up, support the concept of a fruit being selected
var fruits = [
{ name: 'apples', active: true },
{ name: 'bananas', active: false },
{ name: 'cherries', active: false }
]
Then, support that attribute with an ng-class in your angular template:
<ul>
<li data-ng-repeat="fruit in fruits" ng-class="{ active: fruit.active }">{{fruit.name}}</li>
</ul>
Now you can manipulate your fruits array and change which one is selected, for example:
$scope.fruits[2].active = true;
AngularJS is model driven. If you want to change DOM, then change data instead.
You can use $first property to activate the first item of the repeater.
<ul>
<li ng-class="{active : $first}" data-ng-repeat="fruit in fruits">{{fruit}}</li>
</ul>
Or if you want to manually activate any item of the repeater by clicking on it, you can change the activate field of the model object.
<ul>
<li ng-class="{true: 'active', false: ''}[fruit.active]" ng-repeat="fruit in fruits" ng-click="activate(fruit)">{{fruit.name}}</li>
</ul>
Use this data structure
var factory = {
demoFactory: function () {
var fruits = [{
name: 'apples',
active: true
}, {
name: 'bananas',
active: false
}, {
name: 'cherries',
active: false
}]
var factory = {
getFruits: function () {
return fruits;
}
};
return factory;
}
}
And add this in the controller.
$scope.activate = function (fruit) {
console.log(fruit)
fruit.active = true;
}
DEMO
You would set an active property on that model and check for adding it to every element.
var controller = {
demoController: function ($scope, demoFactory) {
$scope.fruits = demoFactory.getFruits();
$scope.fruits[0].isActive = true; // kinda hacky
}
};
<ul>
<li data-ng-repeat="fruit in fruits" ng-class="{ active: fruit.isActive }}">{{fruit}}</li>
</ul>
This isn't exactly how I would do it, but with angular it is always best to edit the model so that you maintain 1 single definitive representation of the state of your application.

AngularJS Error: Unknown provider

I'm getting the classic the classic Error: Unknown provider: UserModelProvider <- UserModel with angular JS. My code looks like this:
var ClabborApp = angular.module('clabbor', []);
ClabborApp.factory('UserModel', function() {
var UserModel = {};
var list = [];
UserModel.getItem = function(index) {
return list[index];
}
UserModel.addItem = function(item) {
list.push(item);
}
UserModel.removeItem = function(item) {
list.splice(list.indexOf(item), 1)
}
UserModel.size = function() {
return list.length;
}
return UserModel;
});
function FollowersCtrl($scope, UserModel) {
$scope.followers = [{
text : 'learn angular',
done : true,
'name' : 'James'
}, {
text : 'build an angular app',
done : false,
'name' : 'John'
}];
}
And my html looks like this:
<html lang="en" ng-app>
<meta charset="utf-8">
<body ng-app="clabbor">
<div class="content follow" ng-controller="FollowersCtrl">
<ul class="clearfix">
<!-- Show max 12 followers -->
<li ng-repeat="follower in followers">
{{follower.name}}
</li>
</ul>
</div>
</body>
</html>
I thought I did it by the book but I am getting the error. Does anyone know what could it be?
Remove the ng-app attribute from the html tag. Here's Jsfiddle that's working: http://jsfiddle.net/eA2xx/. You can't have more than one ng-app.

Categories