AngularJS non-alphabetic orderBy in one of three columns - angularjs

I have a table of data which is three columns. The first two columns should be sorted alphabetically but the third column (value) needs a custom sort: high, medium, low or low, medium, high when reversed.
I have the alphabetical sorting working so far, but having trouble with the custom sort of the 3rd column (value).
JS
(function(angular) {
'use strict';
angular.module('orderByExample2', [])
.controller('ExampleController', ['$scope', function($scope) {
var items = [
{name: 'name1', type: 'Web', value: 'high'},
{name: 'name2', type: 'Email', value: 'medium'},
{name: 'name3', type: 'DNS', value: 'medium'},
{name: 'name4', type: 'Web', value: 'high'},
{name: 'name5', type: 'Web', value: 'medium'},
{name: 'name6', type: 'Email', value: 'high'},
{name: 'name7', type: 'Web', value: 'low'},
{name: 'name8', type: 'FTP', value: 'low'},
{name: 'name9', type: 'Web', value: 'high'}
];
$scope.propertyName = 'value';
$scope.reverse = false;
$scope.items = items;
$scope.sortBy = function(propertyName) {
$scope.reverse = ($scope.propertyName === propertyName) ?
!$scope.reverse : false;
$scope.propertyName = propertyName;
};
}]);
})(window.angular);
HTML
<body ng-app="orderByExample2">
<div ng-controller="ExampleController">
<pre>Sort by = {{propertyName}}; reverse = {{reverse}}</pre>
<hr/>
<button ng-click="propertyName = null; reverse = false">Set to default</button>
<hr/>
<table class="items">
<tr>
<th>
<button ng-click="sortBy('name')">Name</button>
<span class="sortorder" ng-show="propertyName === 'name'" ng-class="{reverse: reverse}"></span>
</th>
<th>
<button ng-click="sortBy('type')">Type</button>
<span class="sortorder" ng-show="propertyName === 'type'" ng-class="{reverse: reverse}"></span>
</th>
<th>
<button ng-click="sortBy('value')">Value</button>
<span class="sortorder" ng-show="propertyName === 'value'" ng-class="{reverse: reverse}"></span>
</th>
</tr>
<tr ng-repeat="item in items | orderBy:propertyName:reverse">
<td>{{item.name}}</td>
<td>{{item.type}}</td>
<td>{{item.value}}</td>
</tr>
</table>
</div>
</body>
Plunker: https://plnkr.co/edit/zBKd3ot22NGZd0y5XTow?p=preview

As #jb-nizet says, you will need a custom function here that would return the value to order each element by. This is a way to implement that function:
function sortingValue(e) {
return ['high', 'medium', 'low'].indexOf(e.value);
}
I've made a fork of your Plunkr.

Related

AngularJS - Removing nested object if attribute equals true

I always get confused when trying to remove/delete nested objects in angularjs. I'm hoping someone can help me with a sample project I'm working on and determine what I'm doing incorrectly.
I have a UI in which there are several rows of nested data within a table. The user will click "Delete" in any row to initiate removing that given row. Then (and this is where I'm struggling) they would click "Remove Deleted Items" to remove all nested objects that have the "deleted" attribute set to true.
I've created an example so showcase what I'm trying to accomplish....
http://plnkr.co/edit/FrKIuEobEBNQ4Kl7TPaC?p=preview
Here's my AngularJS Code:
var myApp = angular.module("fruit", ['ngRoute', 'ngSanitize', 'ui.router']);
myApp.controller("FruitCtrl", function($scope) {
$scope.foods = [{
'id': 1, 'fruits': [{
'id': '1',
'name': 'Apple',
'color': 'Red',
'shape': 'Weird',
'size': 'medium',
'deleted': false
}, {
'id': '2',
'name': 'Orange',
'color': 'Orange',
'shape': 'Sphere',
'size': 'medium',
'deleted': false
}, {
'id': '3',
'name': 'Lime',
'color': 'Green',
'shape': 'Sphere',
'size': 'small',
'deleted': false
}, {
'id': '4',
'name': 'Lemon',
'color': 'Yellow',
'shape': 'Sphere',
'size': 'medium',
'deleted': false
}, {
'id': '5',
'name': 'Banana',
'color': 'Yellow',
'shape': 'Oblong',
'size': 'large',
'deleted': false
}]
}];
$scope.removeDeletedFruit = function(itemId, index) {
for (var i = 0; i < $scope.foods.length; i++) {
if ($scope.foods[i].id === itemId) {
$scope.foods[i].deleted.splice(index, 1);
break;
}
}
}
});
Here's my HTML:
<div class="container">
<h2>Total Fruits: {{foods[0].fruits.length}}</h2>
<button class="btn btn-danger" ng-click="removeDeletedFruit(fruit.id, $index)">Remove Deleted Items</button>
<table class="table" ng-repeat="food in foods">
<thead>
<tr>
<th>Fruit</th>
<th>Shape</th>
<th>Color</th>
<th>Size</th>
<th> </th>
</tr>
</thead>
<tbody>
<tr ng-repeat="fruit in food.fruits" ng-class="{'delete-item': fruit.deleted, '': !fruit.deleted}">
<td>
<span>{{fruit.name}}</span>
</td>
<td>
<span>{{fruit.shape}}</span>
</td>
<td>
<span>{{fruit.color}}</span>
</td>
<td>
<span>{{fruit.size}}</span>
</td>
<td>
<button type="button" class="btn btn-danger" ng-click="fruit.deleted = !fruit.deleted" ng-disabled="fruit.deleted">
<span>Delete</span>
</button>
<button type="button" class="btn btn-neutral" ng-click="fruit.deleted = !fruit.deleted" ng-if="fruit.deleted" ng-disabled="!fruit.deleted">
<i class="fa fa-history fa-1-5x"></i>
<span>Undo</span>
</button>
</td>
</tr>
</tbody>
</table>
</div>
Can someone assist with guiding me in the right direction or what's the best way to make this work?
I changed your function to use the Array.prototype.filter()
$scope.removeDeletedFruit = function(itemId, index) {
angular.forEach($scope.foods, function(fruit){
fruit.fruits = fruit.fruits.filter(function(a){return a.deleted == false})
});
}
demo here

AngularJS : ng-model not working in multiple drop down

I am trying to create dynamic rows based on button click. The rows have drop down boxes. The issue is when I add new row and select an option in the new row the options which I selected in previous rows are also changing, I mean the previous rows options are not binding properly.
My HTML code :
<div id="features" ng-controller="featuresCtrl">
<br>
<div class="row">
<div class="form-group col-md-6">
<table cellpadding="15" cellspacing="10">
<thead>
<tr>
<th style="text-align: center;">Feature</th>
<th style="text-align: center;">Type</th>
<th style="text-align: center;">Value</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr></tr>
<tr ng-repeat="r in rows">
<td>
<select ng-model="r.data.model" ng-options="option.name for option in data.availableOptions"
ng-change="getValues(r.data.model.name)">
<option value="">Select Feature</option>
</select>
</td>
<td>
<select ng-model="r.updateData.model" ng-options="option.name for option in updateData.availableOptions"
ng-change="getBinSet(r.updateData.model.name)">
<option value="">Select Type</option>
</select>
</td>
<td>
<select ng-model="r.binData.model" ng-options="option.name for option in binData.availableOptions">
<option value="">Select Value</option>
</select>
</td>
<td ng-if="showAdd">
<div class="text-center">
<button ng-click="addRow()">Add</button>
</div>
</td>
<td ng-if="showAdd">
<div class="text-center">
<button ng-click="remove($index)">Remove</button>
</div>
</td>
</tr>
<tr>
<td></td>
<td style="align-self: center;">
<button style="align-self: center" ng-click="submitForm(rows)">Submit</button>
</td>
<td></td>
</tr>
</tbody>
</table>
<br>
</div>
My angular JS code :
'use strict';
var testControllers = angular.module('testControllers');
testControllers.controller('featuresCtrl', ['$scope','$route','$filter', '$http', '$location','$window','$timeout', 'NgTableParams',
function($scope, $route, $filter, $http, $location, $window, $timeout, NgTableParams) {
$scope.rows = [{}];
$scope.nrows = [];
$scope.showAdd = false;
$scope.addRow = function() {
$scope.rows.push({
});
};
$scope.remove = function(index) {
$scope.rows.splice(index, 1);
};
$scope.submitForm = function(rows) {
console.log("rows", rows);
};
$scope.data = {
model: null,
availableOptions: [
{ name: 'TestA'},
{ name: 'TestB'},
{ name: 'TestC'},
{ name: 'TestD'}
]
};
$scope.getValues = function (featureType) {
console.log("getValues", featureType);
$scope.showAdd = false;
if (featureType != null) {
$http.get('/getPropensityValues.do', {params: {'featureType': featureType}}).success(function (data) {
var test = [];
angular.forEach(data, function (item) {
test.push({name: item});
});
$scope.updateData = {
model: null,
availableOptions : test
};
});
}
};
$scope.getBinSet = function (featureType) {
console.log("getBinSet", featureType);
$scope.showAdd = true;
if (featureType != null) {
$scope.binData = {
model: null,
availableOptions: [
{name: '1'},
{name: '2'},
{name: '3'},
{name: '4'},
{name: '5'},
{name: '6_10'},
{name: '10_15'},
{name: '16_20'},
{name: '21_25'},
{name: '26_30'},
{name: '31_35'},
{name: '36_40'},
{name: '41_45'},
{name: '46_50'},
{name: '>50'}
]
};
}
};
}]);
Can some one tell me what I am doing wrong here ? I tried with another example - https://plnkr.co/edit/Jw5RkU3mLuGBpqKsq7RH?p=preview
Even here I am facing same issue when selecting the 2nd row 1st row also changing. Is it wrong to use r.data.model to bind each row's values ?
I updated your plunker to work:
https://plnkr.co/edit/4sJHHaJPEuYiaHjdnFBp?p=preview
You weren't defining what the model was when you were redefining the options menus (side note: you should leverage underscore.js's difference function within a filter to create the appropriate display options dynamically)
Anyway, in your addRow() function, I changed it from this:
if(val=== 'TestB') {
$scope.data1 = {
model: null,
availableOptions: [
{ name: 'TestA'},
{ name: 'TestC'},
{ name: 'TestD'}
]
};
}
to this:
if(val=== 'TestB') {
$scope.data1 = {
model: 'TestB',
availableOptions: [
{ name: 'TestA'},
{ name: 'TestC'},
{ name: 'TestD'}
]
};
}
Let me know if this helps
UPDATE:
I recreated the functionality from scratch because I think you were overthinking things. All that is needed here is very simple ng-repeat, ng-options, and ng-model bindings.
<tr ng-repeat="r in rows track by $index">
<td>
<select ng-model="r.name"
ng-options="option.name as option.name for option
in availableOptions">
<option value="">Select Value</option>
</select>
</td>
<td>
<input type="button" ng-click="addRow()" value="Add">
</td>
<td>
<input type="button" ng-click="deleteRow($index)"
value="Delete">
</td>
</tr>
and for the angular
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.rows = [{name:""}];
$scope.addRow = function(){
$scope.rows.push({name:""});
}
$scope.availableOptions = [
{ name: 'TestA'},
{ name: 'TestB'},
{ name: 'TestC'},
{ name: 'TestD'}
];
$scope.deleteRow = function(index){
$scope.rows.splice(index,1);
}
});
I didn't throw in the difference thing yet, but it should be easy.

How to use an array on ng-model

This is my code http://plnkr.co/edit/oxtojjEPwkKng9iKkc14?p=preview
And I want to save object of sport and punctuation in an array, if there are one or more sports selected save it in the array like this:
likes[
{sport: 'futball', points: 1}, {sport: 'tennis', points: 1}
]
thanks!
You have to keep practicing your English a little bit more (you can ask me on the comment section in spanish if you are strugling)
I think what you are trying to do is to have a single select to be able to choose the sport and score,
Html:
<body ng-app="myapp">
<div class="main-container" ng-controller="main" ng-init="darr.dept=dept2">
<div class="client-area">
<label fo.table-container tabler="txt">Score</label>
<input type="text" id="name-txt" placeholder="Assign the score" ng-model="name">
<br />
Sport
<select ng-model="dept" ng-options="deptOpt.value as deptOpt.name for deptOpt in deptList"></select>
<br />
<button ng-click="add()">Add Item</button>
<table id="tab">
<thead>
<tr id="trow">
<th>Score</th>
<th>Sport</th>
<th>Options</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="ar in arr">
<td>{{ar.name}}</td>
<td>{{ar.dept}}</td>
<td>
<button ng-click="del($index)">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
js:
var app = angular.module("myapp", []);
app.controller('main', function ($scope) {
$scope.arr = [];
$scope.deptList = [{
name: 'Football',
value: 'football'
}, {
name: 'Tennis',
value: 'Tennis'
}, {
name: 'Baseball',
value: 'baseball'
}];
$scope.dept = "football";
$scope.name = "";
$scope.add = function () {
this.arr.push({
name: this.name,
dept: this.dept
});
};
$scope.del = function (ind) {
this.arr = this.arr.splice(ind, 1);
};
$scope.editStudent = function(student) {
console.log(student);
};
});
https://jsfiddle.net/azweig/v5kbsudy/1

Angular angucomplete-alt cannot populate the price

var app = angular.module('app', ["angucomplete-alt"]);
app.controller('MainController', function($scope) {
$scope.countries = [
{name: 'Hosting 1', code: '100.00'},
{name: 'Hosting 2', code: '200.00'},
{name: 'Hosting 3', code: '300.00'},
{name: 'Hosting 4', code: '400.00'},
{name: 'Hosting 5', code: '500.00'},
{name: 'Hosting 6', code: '600.00'},
];
$scope.countrySelected = function(selected) {
//$scope.invoice.item.lol = 1;
window.alert('You have selected ' + selected.title);
};
$scope.taxesData = {
singleSelect: null,
availableOptions: [
{id: '6.50', name: '6,5%'},
{id: '16.00', name: '16%'},
{id: '23.00', name: '23%'}
],
selectedOption: {id: '23.00', name: '23%'}
};
$scope.invoice = {
items: [{
description: '',
}]
};
$scope.addItem = function() {
$scope.invoice.items.push({
description: '',
price: 10.99,
});
};
$scope.removeItem = function(index) {
$scope.invoice.items.splice(index, 1);
};
$scope.total = function() {
var total = 0;
angular.forEach($scope.invoice.items, function(item) {
total += item.qty * item.price;
})
return total;
};
$scope.taxtotal = function() {
var taxtotal = 0;
angular.forEach($scope.invoice.items, function(item) {
taxtotal += item.qty * item.price * item.taxesData.repeatSelect * 0.01;
})
return taxtotal;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!--ng-controller="MainController"-->
<div ng-app="app"><div ng-controller="MainController">
<table class="table table-condensed table-striped">
<tr>
<th>Product Name</th>
<th>Item Price</th>
<th>Qty</th>
<th>Tax Rate</th>
<th>Line Total</th>
<th>Line Taxes Total</th>
<th></th>
</tr>
<tr ng:repeat="item in invoice.items">
<td angucomplete-alt id="ex1" placeholder="Search countries" maxlength="50" pause="100" selected-object="selectedCountry" local-data="countries" search-fields="name" title-field="name" minlength="1" input-class="form-control form-control-small" match-class="highlight"></td>
<td><input type="text" value="{{selectedCountry.originalObject.code}}"></td>
<td><input type="text" ng:model="item.qty" ng:required class="input-mini"></td>
<!--<td><input type="text" ng:model="item.taxRate"class="input-small"></td>-->
<td>
<select name="repeatSelect" ng-model="item.taxesData.repeatSelect">
<option ng-repeat="option in taxesData.availableOptions" value="{{option.id}}">{{option.name}}</option>
</select>
</td>
<td>{{item.qty * item.mama | currency}}</td>
<td>{{item.qty * itme.mama * item.taxesData.repeatSelect * 0.01 | currency}}</td>
<td>
[<a href ng:click="removeItem($index)">X</a>]
</td>
</tr>
<tr>
<td><a href ng:click="addItem()" class="btn btn-small">add item</a></td>
<td></td>
<td>Totals:</td>
<td></td>
<td>{{total() | currency}}</td>
<td>{{taxtotal() | currency}}</td>
</tr>
</table>
</div>
</div></div>
As you can see in this jfiddle I am using angular with angucomplete-alt plugin to manage an order form.
I have a scope "countries" which feed the autocomplete box.
Now i am trying to ,
when choosing a country (product :P) i want the field Item Price to feeded with the correct value (e.g. if i select hosting 1, the Item price must completed with 100.00 value.
The problem is that :
1) If I set ng:model to this field (because I want to use the price for the totals) the field does not completed.
2) If I set just value="{{selectedCountry.originalObject.code}}, the field completed but I haven't a ng:object to use it for the totals.
It should be working if you set ng:model as the following, for your Price input field:
<input type="text" ng:model="selectedCountry.originalObject.code">
See working fiddle

ngTableParams Pagination with $http.get

Working on an AngularJS project and I've ran into the following problem:
When using locally stored / hard coded data, the pagination works fine.
When using remotely stored data, the pagination does not work properly.
I have searched quite a bit, but couldn't find the solution to my problem, so here are the code snippits:
The HTML:
<div ng-controller="ngTableCtrl">
<p><strong>Pagina:</strong> {{tableParams.page()}}</p>
<p><strong>Aantal weergegeven:</strong> {{tableParams.count()}}</p>
<table ng-table="tableParams" class="table table-striped" template-pagination="custom/pager">
<tr ng-repeat="x in names">
<td data-title="'Name'">{{x.Name}}</td>
<td data-title="'City'">{{x.City}}</td>
<td data-title="'Country'">{{x.Country}}</td>
</tr>
</table>
<script type="text/ng-template" id="custom/pager">
<ul class="pager ng-cloak">
<li ng-repeat="page in pages"
ng-class="{'disabled': !page.active, 'previous': page.type == 'prev', 'next': page.type == 'next'}"
ng-show="page.type == 'prev' || page.type == 'next'" ng-switch="page.type">
<a ng-switch-when="prev" ng-click="params.page(page.number)" href="">« Previous</a>
<a ng-switch-when="next" ng-click="params.page(page.number)" href="">Next »</a>
</li>
<li>
<div class="btn-group">
<button type="button" ng-class="{'active':params.count() == 2}" ng-click="params.count(2)" class="btn btn-default">2</button>
<button type="button" ng-class="{'active':params.count() == 5}" ng-click="params.count(5)" class="btn btn-default">5</button>
<button type="button" ng-class="{'active':params.count() == 10}" ng-click="params.count(10)" class="btn btn-default">10</button>
<button type="button" ng-class="{'active':params.count() == 15}" ng-click="params.count(15)" class="btn btn-default">15</button>
</div>
</li>
</ul>
</script>
</div>
The JS:
app.controller('ngTableCtrl2', function ($scope, $http, $filter, ngTableParams) {
$http.get('http://www.w3schools.com/angular/customers.php')
.success(function (response) {$scope.names = response.records;});
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 5, // count per page
sorting: {
name: 'asc' // initial sorting
}
}, {
total: data.length, // length of data
getData: function ($defer, params) {
// use build-in angular filter
var orderedData = params.sorting() ? $filter('orderBy')(data, params.orderBy()) : data;
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
});
The webpage ( live version: http://178.62.232.175:8080/STANDARD/#/app/table/data ) shows all results in the first table (remote, from $http.get), whilst the second table, shows only the set results?! (2, 5, 10, 15)
The code is identical, except for:
<tr ng-repeat="x in names">
used to display remote data and is replaced by:
<tr ng-repeat="x in $data">
to display raw data as such:
var data = [{
Name: "Alfreds Futterkiste", City: "Berlin", Country: "Germany"},{
Name: "Ana Trujillo Emparedados", City: "México D.F.", Country: "Mexico"},{
Name: "Antonio Moreno Taquería", City: "México D.F.", Country: "Mexico"},{
Name: "Around the Horn", City: "London", Country: "UK"},{
Name: "B's Beverages", City: "London", Country: "UK"},{
Name: "Berglunds snabbköp", City: "Luleå", Country: "Sweden"},{
Name: "Blauer See Delikatessen", City: "Mannheim", Country: "Germany"},{
Name: "Blondel père et fils", City: "Strasbourg", Country: "France"},{
Name: "Bólido Comidas preparadas", City: "Madrid", Country: "Spain"},{
Name: "Bon app", City: "Marseille", Country: "France"},{
Name: "Bottom-Dollar Marketse", City: "Tsawassen", Country: "Canada"},{
Name: "Cactus Comidas para llevar", City: "Buenos Aires", Country: "Argentina"}
];
The pagination of the second table works as it should. What must I edit to make it work with remote data?
First of all your code is using the local data array as a source in ngTables getData callback and it is not clear what you are presenting as a comparison since you did not actually try AJAX Data Loading from the official examples .
Instead I would expect it to have an api call to the server using $http.get.
Remember for server side paging to work you must update the total count each time you query for data because they may have changed. Also you will have to consider a server side solution for sorting as well.
Here is a working sample using the github api as a test service.
var app = angular.module('main', ['ngTable']);
app.controller('MainCtrl', function($scope, $http, ngTableParams) {
$scope.tableParams = new ngTableParams({
page: 1,
count: 5,
}, {
getData: function ($defer, params) {
var page = params.page();
var size = params.count();
var testUrl = 'https://api.github.com/search/repositories';
var search = {
q: 'angular',
page: page,
per_page: size
}
$http.get(testUrl, { params: search, headers: { 'Content-Type': 'application/json'} })
.then(function(res) {
params.total(res.data.total_count);
$defer.resolve(res.data.items);
}, function(reason) {
$defer.reject();
}
);
},
});
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/ng-table/0.3.3/ng-table.min.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ng-table/0.3.3/ng-table.min.js"></script>
<div ng-app="main" ng-controller="MainCtrl">
<table ng-table="tableParams" class="table table-striped table-bordered table-hover table-condensed">
<tr ng-repeat="repo in $data">
<td data-title="'id'">{{repo.id}}</td>
<td data-title="'name'">{{repo.name}}</td>
<td data-title="'owner'">{{repo.owner.login}}</td>
</tr>
</table>
<div>

Resources