Angular ng-repeat in a ul needs to skip a specific entry - angularjs

I have a simple dropdown that lists the available languages. The page starts in a default language and the user may select from the list.
The list is held in a JSON array and there is a scope variable to holds the currently selected language (being the default language upon start).
The dropdown (ul) is built using ng-repeat over the JSON, so the code would look:
<li ng-repeat="On_Lang in All_Langs"...>
Now, I want to skip the language that is currently being selected. For instance, if the list contains EN, FR, ES, PO, ZU and the current language is PO, when dropping the list it would show EN, FR, ES, ZU. If I select ES, it will be removed from the list and PO will appear.
I thought of adding an ng-if to the li but that is where the loop is taking place.

Since you didn't provide any code it's a bit hard to see what's your structure or anything, but for sure you can create a custom filter to "exclude" the selected option.
I made a simple demo and it should point you to the right direction, take a look:
(function() {
'use strict';
angular.module('app', [])
.controller('mainCtrl', function() {
var vm = this;
vm.languages = ["EN", "FR", "ES", "PO", "ZU"];
})
.filter('customFilter', function() {
return function(items, choice) {
if (!choice) {
return items;
}
return items.filter(function(element) {
return element !== choice;
});
}
});
})();
<!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 as main">
<select ng-options="language for language in main.languages" ng-model="main.selectedLang">
<option value="" label="Select the language"></option>
</select>
<ul>
<li ng-repeat="language in main.languages | customFilter: main.selectedLang track by $index" ng-bind="language"></li>
</ul>
</body>
</html>

Related

Angular JS - display select option based on boolean value of dropdown

Can we display alias name in the select options of dropdown using Angular JS
Issue :
Trying change Boolean value true to Ascending and false to Descending in the display of dropdown options and also trying to retain boolean value on selection of alias name - Ascending or Descending
HTML:
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
Trying to show dropdown options Ascending or Descending instead of true or false<br><br>
<select ng-model="selectedName" ng-options="x.ascending for x in names">
</select><br><br>
{{selectedName}}
</div>
</body>
</html>
JS:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.names = [{"name":"xxxx","ascending":true},{"name":"yyyy","ascending":false}];
});
http://codepen.io/nagasai/pen/ZBMLep
If you wish to show Ascending/Descending instead of true/false then you can just add one ternary condition like below.
<select ng-model="selectedName" ng-options="(x.ascending ? 'Ascending' : 'Descending') for x in names track by x.ascending"></select>

How to pass JSON response to model for use in GET request

I'm accessing an API which returns some JSON about nutritional information. I'm able to store the response in the model, display it, all that good stuff. I just chuck it into $scope.response = data.item.name but there is another property which I would like to use to form a new request to the server.
I want to take data.item.ndbno, store it in $scope.querySelection = data.item.ndbno and use it as a parameter in the new request. I have tried using ng-value={{item.ndbno}}, and accessing it directly via index in the model alone. Basically for the end resoult, I would like to be able to click on any result in the list, and send a get request with that ndbno to the server. Currently the code sends an undefined ndbno like so
POST http://api.nal.usda.gov/ndb/reports/?ndbno=undefined&type=b&api_key=DEMO_KEY&format=json&callback=JSON_CALLBACK 400 (Bad Request).
I don't know what I'm doing wrong. I'm sorry if this has an obvious solution to someone who's seasoned, but I'm a newbie, and I never used jQuery.
Here's my complete code. And just as a show of gratitude, whomever can help me, I will credit in the credits of the finished app.
<!DOCTYPE html>
<html lang="en" ng-app="sugarApp">
<head>
<meta charset="UTF-8"/>
<title>Sugar App</title>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/0.9.4/angular-material.min.css">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.css"/>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js"></script>
</head>
<body ng-controller="loadingController">
<div class="alert alert-info" ng-show="loading">Loading</div> <!-- show/hide based on the truthy or falsey value of $scope.loading-->
<div ng-controller="sugarController">
<form name="searchForm" ng-submit="doSearch()">
<input type="text" ng-model="queryInput" placeholder="Search a food or food product">
<input type="submit" value="Search">
</form>
<ul>
<div ng-show="query">
Results for '{{baseList.q}}'
<li ng-repeat="item in queryResult">
<!-- the problem : ndbno parameter is not being passed, and as a result the request has an undefined value
tried: baseList.ndbno, item.ndbno, $scope.baseList.ndbno, ng-value, bracket syntax [], other things i'm forgetting-->
<a href ng-click="showResults()">{{item.name}}, {{item.ndbno}}</a>
<span ng-model="ndbnum" ng-bind="item.ndbno"></span>>
</div>
</li>
<md-card>
<md-card-content>
The amount of sugar in <strong>{{prodDetail.nutrients[8].measures[3].eqv * .0353}}</strong>oz of <strong>{{prodDetail.name}}</strong> is <strong>{{prodDetail.nutrients[8].measures[3].value}}g</strong>, or <strong>{{prodDetail.nutrients[8].measures[3].value / 7}} circus peanuts</strong>, or <strong>{{prodDetail.nutrients[8].measures[3].value / 4}} teaspoons</strong> of granulated sugar.
<footer>
<small>Source: National Nutrient Database for Standard Reference - Release {{baseReport.sr}}</small>
</footer>
</md-card-content>
</md-card>
</div>
</ul>
<div ng-show="result"> <!-- show/hide based on the truthy or falsey value of $scope.result-->
The amount of sugar in {{baseList.sr}} of {{prodDetail.name}} is {{prodDetail.amount}} or circus peanuts or teaspoons of granulated sugar.
</div>
</div>
<script>
/* TODO
high
clean up code: remove redundancies
figure out how to pass the ndbno result to $scope.querySelection
low
replace deprecated .success with .then
reformat get requests into factory
*/
angular.module('sugarApp',[]).controller('sugarController',['$scope','$http',function($scope,$http){
$scope.doSearch = function(){
$scope.$emit('LOAD'); //using $emit to signal when/vhen not to show the loading indicator
$scope.$emit('UNQUERY'); //using $emit to signal when/when not to show the search results view
$scope.searchUrl = 'http://api.nal.usda.gov/ndb/search/';
$scope.testUrl = 'http://api.nal.usda.gov/ndb/reports/?ndbno=14400&type=f&format=json&api_key=DEMO_KEY';
$scope.api_key = '&api_key=DEMO_KEY';
$scope.fmtJson = '?format=json';
$scope.q = '&q=';
$scope.callback = '&callback=JSON_CALLBACK';
$scope.query = $scope.queryInput;
$scope.fullUrl= $scope.searchUrl + $scope.fmtJson + $scope.q + $scope.query + $scope.api_key + $scope.callback;
$scope.placeholder = "Search for a food or food product";
//temporary comment out $scope.baseReport = {}; //initialize a blank baseReport array
$http.get($scope.fullUrl)
.success(function(data){
//$scope.baseReport=data.report;
$scope.baseList=data.list;
$scope.queryResult=data.list.item;
$scope.ndbnum = data.list.item.ndbno;
$scope.$emit('UNLOAD');
$scope.$emit('QUERY');
$scope.$emit('NORESULT');
})}
$scope.showResults = function(){
$scope.$emit('UNQUERY');
$scope.$emit('LOAD');
$scope.$emit('RESULT');
$scope.resultBaseUrl = 'http://api.nal.usda.gov/ndb/reports/';
$scope.ndb = '?ndbno=';
$scope.querySelection = $scope.ndbnum;
$scope.rtype = '&type=b'
$scope.fmtJson = '&format=json';
$scope.api_key = '&api_key=DEMO_KEY';
$scope.callback = '&callback=JSON_CALLBACK';
//temporary comment out $scope.baseReport = {};
$scope.resultUrl= $scope.resultBaseUrl + $scope.ndb + $scope.querySelection + $scope.rtype
+ $scope.api_key + $scope.fmtJson + $scope.callback;
$http.post($scope.resultUrl)
.success(function(data){
$scope.baseReport=data.report;
$scope.prodDetail=data.report.food;
$scope.$emit('UNLOAD');
})
}
}])
//setting up scope emit flags for use in showing/hiding view elements
//used for showing or hiding results div
.controller('resultController', ['$scope', function($scope){
$scope.$on('RESULT',function(){$scope.result=true});
$scope.$on('NORESULT',function(){$scope.result=false});
}]) //used for showing or hiding query list view div
.controller('queryController', ['$scope', function($scope){
$scope.$on('QUERY',function(){$scope.query=true});
$scope.$on('NOQUERY',function(){$scope.query=false});
}]) // used for showing or hiding the loading indicator div
.controller('loadingController',['$scope',function($scope){
$scope.$on('LOAD',function(){$scope.loading=true});
$scope.$on('UNLOAD',function(){$scope.loading=false});
}])
</script>
</body>
</html>
In your code you used ndbno as a property of item
$scope.ndbnum = data.list.item.ndbno;
but ndbno is not a direct property of data.list.item instead it's a property of a object which is in array
If wanna access ndbno you have to access via index
like
console.log(data.list.item[0].ndbno);
Or without an index you could try something like this.
The html:
<li ng-repeat="item in queryResult track by $index">
<a href ng-click="showResults(item.ndbno, $index)">{{item.name}}, {{item.ndbno}}</a>
</li>
The angular:
$scope.showResults = function(ndbno, id){
.
.
.
// with an index
$scope.ndbnum = queryResult[id].ndbno
// OR a bit easier without an index
$scope.ndbnum = ndbno
.
.
.
}
It can get overly complicated to track by $index, because each ng-repeat has its own $index, and those can be nested, so it can be difficult to tell which $index is being used in a large template.
I would recommend just passing the value directly to the controller. However, if you need to know which object it did come from then using $index is your next best.
Angular will automatically attach a $index to the ng-repeat scope, and its not necessary to do a track by you can just use $index, but then it gets confusing which $index is being used, figuring out a parents $index can get tricky unless you explicitly set the track by to some other variable name other than $index

Change to AngularJS model not reflected in array when using select

I'm learning AngularJS and am hoping I can get some help with a problem I'm facing.
I have an array of objects(friends) in my controller that I've bound to a select element using ngOptions. Using the dropdown, a user can select a friend and view the friends information (id, name, age, etc).
I have also included a button that allows the user to change the age of the selected friend. When the button is clicked, the friends age is changed and reflected in the UI. However, the age change is not reflected in the array If the user then selects a different friend from the drop down and then selects the original friend, the age shown is the original age before the change.
Hopefully this plunker can clarify my explanation: http://plnkr.co/edit/9yfKSt75BhQDIMZjDLVi?p=preview
angular.module('defaultValueSelect', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.friends = [{id:5, name: "jack", age: 35}, {id:8, name: "jill", age: 38}];
$scope.newAge;
$scope.saveNewAge = function(){
$scope.selectedFriend.age = $scope.newAge;
}
}]);
<!doctype html>
<html ng-app="defaultValueSelect" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="ExampleController">
<form name="myForm">
<label for="mySelect">Choose a friend:</label>
<select name="mySelect" id="mySelect"
ng-options="friend.name for friend in friends track by friend.id"
ng-model="selectedFriend"></select>
</form>
<hr>
<tt>selected friend = {{selectedFriend}}</tt><br/>
<input type="text" class="form-control" ng-model="newAge">
<button ng-click="saveNewAge()">Update age</button>
</body>
</html>
My background is in C++ and C#. In those languages, a problem like this would be due to copying an object from the array and changing it rather than changing a reference to the object in the array. I've been searching the internet, and it seems like my problem may have something to do with what scope I'm in, but I'm not sure.
If you just add a for loop into your saveNewAge function to match the selected person to the person in the array (I used id to match) and set the age there it should do what you want.
$scope.saveNewAge = function() {
$scope.selectedFriend.age = $scope.newAge;
for (var i = 0; i < $scope.friends.length; i++) {
if ($scope.friends[i].id === $scope.selectedFriend.id)
$scope.friends[i].age = $scope.selectedFriend.age;
}
}
As is mentioned in the ngOptions documentation
Note: By default, ngModel watches the model by reference, not value. This is important when binding any input directive to a model that is an object or a collection.

selection not reflecting in select input with ngOptions

Angular is not able to reflect selected option in select input. Below is my complete code. Hospital One should have been selected, but not happening, what could be the reason ?
I've also put the same code snippet in JsBin also.
angular.module('testApp', [
])
.controller('AppController', function(){
var vm = this;
//
vm.schedule = {
date : "2015-5-25",
organization : {
"_id":"55df26cf756549c15b5fbcd2",
"name":"Hospital One",
"kind":"HOSPITAL",
"email":"somehospital1#hospital.com"
}
};
//
vm.user = {
name : "Some user name",
affiliates : [
{
"_id":"55df26ea756549c15b5fbcd5",
"createdOn":"2015-08-27T15:04:10.376Z",
"organization":{
"_id":"55df26cf756549c15b5fbcd2",
"kind":"HOSPITAL",
"name":"Hospital One",
"email":"somehospital1#hospital.com"
}
},
{
"_id":"55df26ea756549c15b5fbcd4",
"createdOn":"2015-08-27T15:04:10.375Z",
"organization":{
"_id":"55dbfd280713a3aa0d85158a",
"kind":"CLINIC",
"name":"Some Clinic",
"email":"someclinic#clinic.com"
}
}
]
};
})
;
<!DOCTYPE html>
<html ng-app="testApp">
<head>
<title>Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
</head>
<body ng-controller="AppController as vm">
<h3>Selected Is : </h3>
<pre>{{ vm.schedule.organization | json }}</pre>
<h3>But selection is not reflecting in select</h3>
<select ng-model="vm.schedule.organization" ng-options="affiliate.organization as affiliate.organization.name for affiliate in vm.user.affiliates | orderBy : 'organization.name' track by affiliate.organization._id">
<option value="">-- Choose Organization --</option>
</select>
</body>
</html>
From ngOptions docs:
select as and track by:
Do not use select as and track by in the same expression. They are not
designed to work together.
Just remove the 'track by' and it'll work fine.
<select ng-model="vm.schedule.organization" ng-options="affiliate.organization as affiliate.organization.name for affiliate in vm.user.affiliates | orderBy : 'organization.name'">
working bin
-----EDIT------
Your options and your selected value are two different objects at first, therefore you'll always see the <-- Choose Organization --> option as selected before changing the select.
In order to solve that you need to bind the selected to be one of the options.
here's a working bin that solves that issue as well

Using AngularJS select ng-options with Semantic UI's dropdown

So Semantic UI appears to the latest 'hot' UI framework which I'm impressed with; however, their dropdown isn't an implementation of the HTML 'select' and 'option' tags but instead custom. For my project, I'm using AngularJS which is phenomenal JavaScript MVW framework.
How can I integrate AngularJS select ng-option with Semantic UI's dropdown? I'm not much of a JS pro. Here's the JSfidde: http://jsfiddle.net/fMUy3/
<!doctype html>
<html ng-app="App">
<body ng-controller="MainCtrl">
<h3>Option 1 (standard)</h3>
<select ng-model="selectedItem" ng-options="c as (c.id + ' - ' + c.name) for c in containers">
<option value="">-- Pick A Container --</option>
</select>
<br>ID: {{selectedItem.id}}
<br>Name: {{selectedItem.name}}
<h3> Semantic UI Dropdown</h3>
<div class="ui selection dropdown ">
<input name="id" type="hidden" value="0">
<div class="text">-- Pick A Container --</div> <i class="dropdown icon"></i>
<div class="menu transition hidden">
<div class="item active">-- Pick A Container --</div>
<div data-value="{{container.id}}" class="item" ng-repeat="container in containers">{{container.name}}</div>
</div>
</body>
</html>
JavaScript:
var app = angular.module('App', []);
app.controller('MainCtrl', function($scope) {
$scope.containers = [
{id: 1, name: 'Box1'},
{id: 2, name: 'Box2'},
{id: 3, name: 'Box3'}];
//$scope.selectedItem = $scope.containers[0];
});
$('.ui.dropdown').dropdown();
Much appreciated!
There were a few things wrong with your fiddle. The first was that the semantic-ui JavaScript was being loaded before jQuery. It depends on jQuery so jQuery must be loaded first. (Also, loading jQuery before AngularJS is recommended.)
The second thing is that the semantic dropdown function was being called before AngularJS had a chance to unroll the repeater that creates the options. This means the options were not there when semantic did its dropdown thing. As a simple solution I made a timeout that would fire on the next processing loop; after AngularJS has done its thing. You can see that semantic dropdown now works
This is more of a simple proof of concept to demo the timing of things and should not be used.
http://jsfiddle.net/fMUy3/1/
$timeout(function(){
$('.ui.dropdown').dropdown();
},0)
How this should be handled is with a directive that will take care of the timings so that you do not need to use the timeout and would not need to specify each dropdown in the controller. Here is the example using a directive (which would handle all cases)
http://jsfiddle.net/fMUy3/7/
app.directive('dropdown', function ($timeout) {
return {
restrict: "C",
link: function (scope, elm, attr) {
$timeout(function () {
$(elm).dropdown().dropdown('setting', {
onChange: function (value) {
scope.$parent[attr.ngModel] = value;
scope.$parent.$apply();
}
});
}, 0);
}
};
});
Your first problem is you need to include semantic.js after jquery.
Second, you can't use ng-options on a div repeater but you can simulate it by using a ng-click
HTML
<div data-value="{{container.id}}" class="item" ng-repeat="container in containers" ng-click="select(container)">
{{container.name}}
</div>
JS
$scope.select = function(container) {
$scope.selectedItem = container;
};
see this updated fiddle

Resources