Conditionally including select options in angular - javascript

I'm using an angular select directive.
<select
ng-model="tune.rating"
ng-options="opt.value as opt.label for opt in dropdowns.rating"
ng-change="update()" >
<option ng-if="tune.rating === -1" value="">-- rate tune --</option>
</select>
I want the default option to only be included when a rating isn't already given, but the ng-if isn't getting applied (both when the controller is loaded and in response to selecting a value)
Is there some way I can get this to work. I can't append the default option conditionally to dropdowns.rating as there are many tunes per page, all of which may be rated or unrated and all of which use the dropdowns.rating array
Note: I don't think my question duplicates this one angularjs Select with filter to filter out the option that's already selected, although they are similar

Use $templateCache and a for loop as an alternative:
var app = angular.module('foo', []);
function foo($templateCache)
{
var tmpl, lister,
ProductData =
{ "odata.metadata": "localhost:51811/odata/$metadata#Products",
"value": [
{
"ID": 1,
"Year": 2017,
"Name": "Hat",
"Price": "15.00",
"Category": "Apparel"
}
]
};
lister = function()
{
var index, replacement = "";
for (index in this)
{
/* Avoid adding the callback function itself to the array */
if (/[^\d]/.test(this[index]) === false)
{
replacement = replacement.concat("<option>",this[index],"</option>");
}
}
return replacement;
};
ProductData.value[0].toJSON = lister;
tmpl = JSON.stringify(ProductData.value[0]);
console.log(tmpl);
$templateCache.put('listContent', tmpl);
}
app.run(foo);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="foo">
<select ng-include="'listContent'"></select>
</div>
References
Using a toJSON Method with JSON.stringify
.toJSON() | Sails.js Documentation
What you didn’t know about JSON.Stringify | CodeKraft
TypeScript: Working with JSON · Choly's Blog

Related

Bind options value to ng-model in angularjs

I'm working on a project, and I need to bind the options value to object key's in such a manner that, on selecting an option, it gives 1, else other variables remain 0.
My HTML Code:-
<select required class="custom-select">
<option disabled>Select an option</option>
<option ng-model="PredictCtrl.detail.building_type_AP">Apartment</option>
<option ng-model="PredictCtrl.detail.building_type_GC">Independent House / Villa</option>
<option ng-model="PredictCtrl.detail.building_type_IF">Independent Floor / Builder's Floor</option>
<option ng-model="PredictCtrl.detail.building_type_IH">Gated Community Villa</option>
</select>
Variable to bind -
PredictCtrl.detail = {
building_type_AP: 0,
building_type_GC: 0,
building_type_IF: 0,
building_type_IH: 0
}
Generally, binding is done with select tag, which gives the value of the selected option, but I want in such a way that, when I click on Apartment option, it's bind variable PredictCtrl.detail.building_type_AP becomes 1, rest remains 0. Similarly, it does with other options.
I want to send the data as the same format through API.
So, please Help me out.
Sorry If I was not very clear with explaining or for any typo.
Thank you in advance.
You should take a look at the NgOptions directive which is the "angularjs" way of working with the select-tag.
It sould be able to fulfill your requirement as you will get the selected option in the SelectedOption object.
Here's an example
angular.module("app",[]).controller("myCtrl",function($scope){
$scope.details =
[
{name:"Apartment", value:1},
{name:"Independent House / Villa", value:2},
{name:"Independent Floor / Builder's Floor", value:3},
{name:"Gated Community Villa", value:4}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
<select required class="custom-select" ng-options="item as item.name for item in details" ng-model="selectedOption">
</select>
<p>SelectedOption: {{selectedOption}}</p>
</div>
None of the answers at my time of writing actually present a functioning solution, so here's one.
Don't scatter ng-model directives across different option elements, it's unnecessary.
You can achieve what you want by using ng-options to enumerate all your choices, a single ng-model to keep track of the selected option, and ng-change to apply the values as you described (i.e. 1 on the selected key, 0 for everything else).
I've assumed you've got a requirement to keep the structure of detail as is. If it can be changed, then I'd recommend associating each labels with each it's respective building_type_ to keep things together.
See below.
angular
.module('app', [])
.controller('PredictCtrl', function () {
this.selectedDetail = null;
this.detail = {
building_type_AP: 0,
building_type_GC: 0,
building_type_IF: 0,
building_type_IH: 0,
};
this.labels = {
building_type_AP: 'Apartment',
building_type_GC: 'Independent House / Villa',
building_type_IF: 'Independent Floor / Builder\'s Floor',
building_type_IH: 'Gated Community Villa',
};
this.changeDetail = function () {
for (var key in this.detail) {
this.detail[key] = +(this.selectedDetail === key);
}
};
});
<script src="https://unpkg.com/angular#1.7.4/angular.min.js"></script>
<div ng-app="app" ng-controller="PredictCtrl as PredictCtrl">
<select
ng-model="PredictCtrl.selectedDetail"
ng-options="key as PredictCtrl.labels[key] for (key, value) in PredictCtrl.detail"
ng-change="PredictCtrl.changeDetail()"></select>
<pre>{{ PredictCtrl.detail | json }}</pre>
</div>
try like this:
in your controller:
$scope.details = [
{
name: "building_type_AP",
value: "Apartment",
state: false
},{
name: "building_type_GC",
value: "Independent House / Villa",
state: false
}/*add more here*/
];
$scope.setActive = function(detail){
detail.state = !detail.state;
}
in html template:
<select required class="custom-select">
<option disabled>Select an option</option>
<option ng-repeat="detail in details" ng-click="setActive(detail)">{{detail.value}}</option>
</select>
in the end just go through $scope.details and parse false to 0 and true to 1 OR just do this inside setActive function

angularjs - setting select element option value with JS object

I am new to AngularJS so please bear with me.
Following is the the JSON string I am trying to bind in the select element:
[
{"Name":"Value 1","ID":1},
{"Name":"Value 2","ID":2},
{"Name":"Value 3","ID":3},
{"Name":"Value 4","ID":4}
]
Following is the JS object for the same:
function NameValue(nameValue){
var self = this;
self.ID = nameValue.ID;
self.Name= nameValue.Name;
}
I am parsing the above JSON string, looping through the objects and pushing items into an array using the above JS object like:
angular.forEach(angular.fromJson(jsonString), function (value, key) {
$scope.Values.push(new NameValue(value));
});
Following is my select with agularjs bindings:
<select ng-model="SelectedName" ng-options="x.Name for x in Values">/select>
When I select a value in the select element, the entire NameValue object is getting set into the SelectedName property which is what I am trying to do.
Now when I try to set the SelectedName property dynamically, the value is not getting selected and an empty option element is getting added in the select element. I used the {{SelectedName}} to check the value when set dynamically and when I select the same value in the select element manually and both are {"ID":2,"Name":"DAO"} which are exactly same. What am I doing wrong here?
The syntax of ng-options is something like this.link
<select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
Suppose you have controller like this
app.controller('MainCtrl', function($scope) {
$scope.Values = [
{"Name":"Value 1","ID":1},
{"Name":"Value 2","ID":2},
{"Name":"Value 3","ID":3},
{"Name":"Value 4","ID":4}
];
$scope.SelectedByName='Value 2'; //Default setting drop down by Name property
$scope.SelectedById=4; //Default setting drop down by ID property
});
If you follow the below syntax then either name or Id property will be set to selected variable.
If you need default selection of drop down then you need to set the respective model in controller.(as above)
HTML :
<body ng-controller="MainCtrl">
By name :
<select ng-options="value.Name as value.Name for value in Values"
ng-model="SelectedByName" ng-change="Print()"></select>
Selected value is : {{SelectedByName}}
<br>
By ID :
<select ng-options="value.ID as value.Name for value in Values"
ng-model="SelectedById" ng-change="Print()"></select>
Selected id is : {{SelectedById}}
</body>
Demo plunker Click here
First of all - you should initialize SelectName in your $scope.
Next you can use:
ng-options="x.id as x.name for x in values"
Can you display {{values}} in your template and it's look good? Maybe you have a problem with redraw template when data is push into value. Check this way also.
here is a working snippet. i guess you didn't defined Values as an array, before pushing anything you have to define the variable as an array.
var app = angular.module('myApp', []);
function NameValue(nameValue) {
var self = this;
self.ID = nameValue.ID;
self.Name = nameValue.Name;
}
app.controller('myCtrl', function($scope) {
$scope.Values = [];
$scope.jsonString = [{
"Name": "Value 1",
"ID": 1
}, {
"Name": "Value 2",
"ID": 2
}, {
"Name": "Value 3",
"ID": 3
}, {
"Name": "Value 4",
"ID": 4
}];
angular.forEach(angular.fromJson( $scope.jsonString), function (value, key) {
$scope.Values.push(new NameValue(value));
});
console.log($scope.Values);
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<select ng-model="SelectedName" ng-options="x.Name for x in Values">/select>
</div>
</body>
</html>
I had the same issue and i found a solution:
Don't use ng-options but <option> tag
<select ng-model="..."> <option ng-repeat="..."> {{ ... }} </option></select>

Angular ng-options track by overriding ng-model default option

I have an ng-options iterating over an object, the key of this object is the value I need the ng-options to be set to.
I set the ng-model in my controller to default the select box.
Using track by breaks the ng-model default, however stopping track by removes the issue but introduces another where the default of the select box is no longer the key of the object.
How can I get around this issue?
The HTML I am using is as follows
<select
class="form-control"
ng-change="flightNumber = airline[0]"
name="airline"
id="airline"
ng-model="airline"
ng-options="airline for (airline, flights) in orderedFlights track by airline">
</select>
In my controller I have the following:
var flights = {
"Airline": {
},
"Airline 2": {
},
"-- No Airline Selected --": [
{
unselected: true
}
];
}
$scope.orderedFlights = flights;
$scope.airline = flights["-- No Airline Selected --"];

Chaining Selects with Angular JS

I am brand new, just experimenting, with AngularJS framework. So I am not sure the approach I have taken is the best/right way.
I'm trying to create a 3 level chained ajax filled select boxes, and it is kind of working, except for a couple of issues.
My actual code uses ajax which is in a factory, but for the sake of the fiddle I just have a controller returning results from an array.
Demo (using arrays, not ajax): http://jsfiddle.net/xxwe1zu8/1/
Issues:
2nd and 3rd level selects don't have a "selected" attribute - ie the one you select doesn't get highlighted.
Ideally I would like the top level categories to be dynamically filled on page load via ajax (or in this example by array) using the same angular function (eg: getSubcategories = function(0, 0) {) rather than hardcoded. Top level categories have a parent of 0.
Bonus: Can the 3rd select box only be shown/visible if there is a sub sub category returned after selecting the sub category? In reality, most sub categories won't have sub sub categories.
var myAppModule = angular.module('myApp',[]);
myAppModule.controller('SearchCtrl', function($scope) {
var self = this;
self.subCategories = [];
self.getSubcategories = function(parent, level) {
theCategories = [];
angular.forEach(sub_category[parent], function(idx, val) {
theCategories.push({id: val, name: idx});
});
self.subCategories[level] = theCategories;
}
});
Thanks
I would suggest to restructure data in an array of objects and get rid of indicies which are seemingly of no use here.
var transport = [
{
name: "Cars",
models: [
{
name: "Hatchback",
variations: ["4 door", "5 door"]
},
{
name: "Sedan",
variations: ["4 door", "5 door"]
},
{
name: "SUV",
variations: ["Medium", "Large"]
}
]
},
...
This allows to make clearer code in template. I am not ControllerAs syntax here since $scope is injected in any way. And it is a better approach if you just start learning AngularJS
<select
ng-model="selectedType"
ng-options="t.name for t in transport"
ng-change = "selectedModel=null;selectedVariation=null">
<option value="">Select type</option>
</select>
<select
ng-model="selectedModel"
ng-options="model.name for model in selectedType.models"
ng-change="selectedVariation=null"
ng-show="selectedType.models">
<option value="">Select model</option>
</select>
<span ng-show="loading">Loading...</span>
<select
ng-model="selectedVariation"
ng-options="variation for variation in variations"
ng-show="variations && !loading">
<option value="">Select variation</option>
</select>
selectedType, selectedModel and selectedVariation are implicitly defined in $scope by ng-model of each select. There is even no mention of them in controller currently. At the same time this properties are used in ng-show to hide select tags which are not relevant in current selection.
The last select (sub subcategory) demonstrates a way to fetch data asynchronously. Let's imagine you don't have a complete tree of data at once and fetch variations from server on model selection. You would place a watch in controller for selectedModel and if it was selected (not emptied) you would launch a request for data and update variations on response
$scope.$watch('selectedModel', function(model){
if(model){
$scope.loading = true;
//setTimeout imitates an ajax request
setTimeout(function(){
$scope.variations = model.variations;
$scope.loading = false;
$scope.$apply();
}, 1000);
}
})
Updated fiddle

Angular filter select lists excluding selected value

I have a dynamic html block for which a user can add multiple select lists. I'm wanting to disable the selections that the user has made in the previous lists by checking using a custom filter. The part i'm struggling with how to pass the dynamic model into the filter and check that the value does not exist on the already generated select lists.
I've created a plunker. I appreciate the help.
<body ng-app="app" ng-init="things=[{id:0,name:'thing1'},{id:1,name:'thing2'},{id:2,name:'thing3'},{id:3,name:'thing4'}]">
<select ng-model="fields.option1" ng-options="thing.name for thing in things | excludeFrom:fields.option2"></select>
<select ng-model="fields.option2" ng-options="thing.name for thing in things | excludeFrom:fields.option1"></select>
<select ng-model="fields.option2" ng-options="thing.name for thing in things | excludeFrom:fields.option1,fields.option2"></select>
angular.module('app',[])
.filter('excludeFrom', [function () {
return function (things, selectedValue) {
if (!angular.isUndefined(things) && !angular.isUndefined(selectedValue)) { //&& selectedValue.length > 0) {
var tempThings = [];
angular.forEach(selectedValue, function (name) {
angular.forEach(things, function (things) {
if (angular.equals(things, selectedValue.name)) {
tempThings.push(things);
}
});
});
return tempThings;
} else {
return things;
}
};
}]);
There is actually a predefined Angular feature that does what you want to do. A filter in Angular can be negated, which means that you can specifically exclude options from your selection. I recommend using ng-init on your selects though, otherwise you might run into undefined filter options.
Here is some code displaying my solution:
<select ng-model="select1" ng-init="select1 = things[0]" ng-options="thing.name for thing in things | filter:{name:'!'+select2.name}"></select>
<select ng-model="select2" ng-init="select2 = things[1]" ng-options="thing.name for thing in things | filter:{name:'!'+select1.name}"></select>
And here is a plnkr showing it in action.
For further reading on filters you might want to check out the API here
You can also handle the select part as an Array like so
<select ng-model="select[0]" ng-init="select[0] = things[0]"
ng-options="thing.name for thing in things | filter:{name:'!'+select[1].name}"></select>
<select ng-model="select[1]" ng-init="select[1] = things[1]"
ng-options="thing.name for thing in things | filter:{name:'!'+select[0].name}"></select>
However if you want to have a dynamic selection, you will have to write a custom filter which i did like so:
Filter:
.filter('exclude', [function () {
return function(input,select,selection){
var newInput = [];
for(var i = 0; i < input.length; i++){
var addToArray=true;
for(var j=0;j<select.length;j++){
if(select[j].name===input[i].name){
addToArray=false;
}
}
if(addToArray || input[i].name === selection.name){
newInput.push(input[i]);
}
}
return newInput;
};
And usage:
<div ng-repeat="sel in select">
<select ng-model="select[$index]" ng-init="sel"
ng-options="thing.name for thing in things | exclude:select:sel"></select>
</div>
And here is a plunkr showing this solution.

Categories

Resources