Angularjs Dropdown won't hold value after refresh - javascript

I have been working on this way too long trying to figure it out.
<select class="form-control"
ng-model="question.sel"
ng-change="updateDropDownQuestion(question,question.sel)">
<option ng-repeat="answer in question.answers" ng-disabled="answer.notAnOption" value="{{answer.acode}}">{{answer.name}}</option>
<option style="display:none" value="NONE">NONE</option>
</select>
Then in my js file:
$scope.updateDropDownQuestion = function(question, answer) {
reset(question.code)
$scope.formData["SOLE/SELECTED_QUESTION"] = question.code
$scope.formData["SOLE/SELECTED_ANSWER"] = answer
$scope.formData[question.code+"/"+answer] = true
var questions = $scope.product.questions
for(i=0; i <questions.length;i++){
if(questions[i].code == question.code){
questions[i].sel = answer
break;
}
}
$scope.refresh()
};
the $scope.refresh() is where it changes back. This renders the screen.
no matter what I do it seems to render the previous state and not the current state of the drop down. This is because I am repainting the screen after the drop down changes.
It seems as though the when the screen repaints it is taking the original value first.
Any thoughts on how I can get the value to "stick" once set?
Do I need to fire some event afterwards?

From Angular official site:
Note: ngModel compares by reference, not value. This is important when binding to an array of objects. You might find this helpful to set the default values of your drop down. See an example below.
angular.module('demoApp', []).controller('DemoController', function($scope) {
$scope.options = [
{ label: 'one', value: 1 },
{ label: 'two', value: 2 }
];
// Although this object has the same properties as the one in $scope.options,
// Angular considers them different because it compares based on reference
$scope.incorrectlySelected = { label: 'two', value: 2 };
// Here we are referencing the same object, so Angular inits the select box correctly
$scope.correctlySelected = $scope.options[1];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="demoApp">
<div ng-controller="DemoController">
<div>
<h2>Incorrect</h2>
<p>We might expect the select box to be initialized to "two," but it isn't because these are two different objects.</p>
<select ng-model="incorrectlySelected"
ng-options="opt as opt.label for opt in options">
</select>
The value selected is {{ incorrectlySelected.value }}.
</div>
<div>
<h2>Correct</h2>
<p>Here we are referencing the same object in <code>$scope.correctlySelected</code> as in <code>$scope.options</code>, so the select box is initialized correctly.</p>
<select ng-model="correctlySelected"
ng-options="opt as opt.label for opt in options">
</select>
The value selected is {{ correctlySelected.value }}.
</div>
</div>
</body>

Try using ng-options to render option elements.
Something along these lines:
<select class="form-control"
ng-model="question.sel"
ng-change="updateDropDownQuestion(question,question.sel)"
ng-options="answer.acode as answer.name in question.answers">
</select>
It also depends on what updateDropDownQuestion is doing, can you provide that?

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

Angular 1.5 "track by" ruines binding in ng-options

I need to select option in combobox from ajax loaded data. That data comes as list of objects. The problem is that ng-option compares objects by reference and thus setting model to objects element results in appearing new empty option in combobox instead of selecting correct option.
The known workaround is to use track by expression.
And here is example code:
var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function($scope) {
$scope.roles =[
{ key:"administrator", value:"ROLE_ADMIN" },
{ key:"operator", value:"ROLE_OPERATOR" },
];
// this emulates data from server
// won't work without 'track by'
$scope.role={ key:"administrator", value:"ROLE_ADMIN" };
});
Template:
<body ng-app="myApp" ng-controller="myCtrl">
0: <input ng-model="roles[0].key" />
<br>
1: <input ng-model="roles[1].key" />
<br>
select role: <select ng-model="role" ng-options="r.key for r in roles track by r.value">
</select>
<pre>selected role={{role|json}}</pre>
</body>
Here another problem arises. When one selects role in combobox and then
changes it's "key" property in textbox, then selected role stays unchanged. So it looks like binding is suddenly gets broken.
https://jsfiddle.net/xLqackxw/8/
from Angular documentation https://docs.angularjs.org/api/ng/directive/ngOptions
<select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
So:
<select ng-model="role" ng-options="r as r.key for r in roles track by r.value"></select>
'$scope.role' value will be object like { key:"administrator", value:"ROLE_ADMIN" } or { key:"operator", value:"ROLE_OPERATOR" }

How to Pre populate drop down

I have the Drop down list which is populated from a GetJSON call as shown below
VIEW
#{
var NoticeFilter =(X.Models.Y.Z.NoticesEntity) ViewData["NoticeFilter"];
}
<div class="form-group">
<label>Field Office</label>
<select data-bind="options: FieldOffice, value: selectedFieldOffice, optionsCaption:'Choose...', optionsValue:'FieldOfficeID', optionsText:'Name'">
#if(NoticeFilter!=null)
{
<option value="#NoticeFilter.FieldOfficeID" selected></option>
}
</select>
</div>
When I direct to this page and send data into the NoticeFilter I want the value in drop-down pre-selected with the value in Noticefilter among the other values .How do I achieve this
I was wondering if there is way in razor HTML where I can set a default value to Drop-Down after the data-binding from KO JS
Have you tried this?
<script>
var str = #Html.Raw(Json.Encode(ViewData["Text"]));
</script>
WORKING
After few attempts I found this as one way to access the ViewData or ViewBag in my JS
I used the KO JS optionsAfterRender as below
VIEW
<select data-bind="options: SubType, value: selectedSubType, optionsValue:'SubTypeID', optionsText:'SubTypeDescription',optionsAfterRender:function(){setOptionST(#Noticefilter .SubTypeID);}"></select>
JS
In the view model
self.setOptionST = function (x) {
//here we can do whatever is intended to in my case to set the initial value in dropdown
self.selectedSubType(x);
};

AngularJS null value for select

I couldn't find an elegant way for setting null values with a <select> using AngularJS.
HTML :
<select ng-model="obj.selected">
<option value=null>Unknown</option>
<option value="1">Yes</option>
<option value="0">No</option>
</select>
{{obj}}
JS :
$scope.obj ={"selected":null};
When the page is loaded, the first option is selected, which is good, and the output is {"selected":null}. When that first option is reselected after having switch to another one, the output becomes {"selected":"null"} (with the quotes), which is not what I would expect.
Running example :
http://plnkr.co/edit/WuJrBBGuHGqbKq6yL4La
I know that the markup <option value=null> is not correct. I also tried with <option value=""> but it corresponds to an empty String and not to null : the first option is therefore not selected and another option which disappears after the first selection is selected by default.
Any idea ?
This should work for you:
Controller:
function MyCntrl($scope) {
$scope.obj ={"selected":null};
$scope.objects = [{id: 1, value: "Yes"}, {id: 0, value: "No"}]
}
Template:
<div ng-controller="MyCntrl">
<select ng-model="obj.selected"
ng-options="value.id as value.value for value in objects">
<option value="">Unknown</option>
</select>
<br/>
{{obj}}
</div>
Working plnkr
You should use ng-options with select.
You can use the ngOptions directive on the select. According to the documentation:
Optionally, a single hard-coded <option> element, with the value set to an empty string, can be nested into the <select> element. This element will then represent the null or "not selected" option. See example below for demonstration.
<select ng-model="obj.selected" ng-options="key as label for (key, label) in ['No', 'Yes']">
<option value="">Unknown</option>
</select>
It's obviously a better idea to define the options list directly in the controller.
Try using ng-options instead of manually creating tags, as in this example, lightly-edited from the Angular docs:
http://plnkr.co/edit/DVXwlFR6MfcfYPNHScO5?p=preview
The operative parts here are lines 17, defining a 'colors' object, and the ng-options attributes iterating over those colors to create options.
If you REALLY want to use null, see below. You need to use ng-options and let Angular handle the mapping:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Color selector</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.8/angular.min.js"></script>
</head>
<body ng-app="">
<script>
function MyCntrl($scope) {
$scope.obj ={"selected":null};
$scope.objStates = [{key:"Unknown", value:null}, {key:"Yes", value:1}, {key:"No", value:0}]
$scope.$watch('obj.selected', function(newVal){
console.log(newVal);
})
}
</script>
<div ng-controller="MyCntrl">
<select ng-model="obj.selected" ng-options="state.value as state.key for state in objStates">
</select>
<br/>
{{obj}}
</div>
</body>
</html>
I ran into the same Problem but could not solve it via 'ng-options'. My solution is:
module.directive('modelToNull', [function () {
return {
scope: {
check: "&modelToNull"
},
require: 'ngModel',
link: function ($scope, element, attrs, ngModelController) {
ngModelController.$parsers.push(function (value) {
return value == null || $scope.check({value: value}) ? null : value;
});
}
};
}]);
You can use it like this:
<select ng-model="obj.selected" model-to-null="value == 'null'">
<option value="null">Unknown</option>
<option value="1">Yes</option>
<option value="0">No</option>
</select>
Can you try to use parseInt on the value? For example, both "1" and "0" will equal their respective integer values. If you run the empty string through parseInt you can easily get NaN.
> parseInt("") = NaN
> parseInt("0") === 0
> parseInt("1") === 1
Without the possibility of using ng-options I present another fix.
I've been battling this a couple of months now, using solutions presented on this question and I don't know how nobody posted this:
<option value="null"></option>
This should work on Angular 1.6 and above for sure when you are using ng-repeat for options instead of ng-options.
It's not ideal but since we are used to work on legacy code this simple fix could save your day.
the only way you can achieve that is by using a onchange event and restoring the object as initialized any other attempt to set the selected to null will remove the property from the object.
$scope.setValue=function(val){
if($scope.obj.selected=="null")
$scope.obj ={"selected":null};
}
<select ng-change="setValue()" ng-model="obj.selected">
<option value=null ng-click="obj.selected=null">Unknown</option>
<option value="1">Yes</option>
<option value="0">No</option>
</select>
this is a bad idea, you should always have values in your model instead of playing around with null and undefined
This is much easier on Angular2/Angular where you can just use
<option [value]="null">Unknown</option>
This value is no longer a string, but a real null value.

Angular, boolean value in a select box

I want to set a boolean value to true or false using a select here is my code:
<select class="span9" ng-model="proposal.formalStoryboard">
<option value="false">Not Included</option>
<option value="true">Included</option>
</select>
The value (proposal.formalStoryboard) is set properly to true or false but the change are not reflected on the select box when the value is already assigned.
I tried ng-value="true" and ng-value="false" instead of just value but it's not working as well.
EDIT: Commentors have pointed out that my original solution did not work as claimed. I have updated the answer to reflect the correct answer given by others below (I cannot delete an accepted answer).
For Angular 1.0.6, consider this HTML:
<div ng-app="">
<div ng-controller="MyCntrl">
<select ng-model="mybool"
ng-options="o.v as o.n for o in [{ n: 'Not included', v: false }, { n: 'Included', v: true }]">
</select>
<p>
Currently selected: <b>{{ mybool }}</b> opposite: {{ !mybool }}
</p>
</div>
</div>
And this JavaScript:
function MyCntrl($scope) {
$scope.mybool = true;
}
Here is a working DEMO for Angular 1.0.6 and here is a working DEMO for Angular 1.3.14, which is slightly different.
Just do like this:
<select ng-model="someModel" ng-options="boolToStr(item) for item in [true, false]">
</select>
and define:
$scope.boolToStr = function(arg) {return arg ? 'Included' : 'Not included'};
Why not just use this?
<select class="form-control" ng-options="(item?'Included':'Not Included') for item in [true, false]"></select>
If you are using angularjs version >= 1.2.0 you will have access to the directive ng-value
You can use the ng-value on an option element. Your htmls would work like this.
<select ng-model="proposal.formalStoryboard">
<option ng-value="true">Included</option>
<option ng-value="false">Not Included</option>
</select>
It also works on radio and checkboxes.
I would recommend using a directive for this. As usual, I try to stay away from timeouts and other async operations in preference of a more authoritative and direct control.
directives.directive('boolean', function() {
return {
priority: '50',
require: 'ngModel',
link: function(_, __, ___, ngModel) {
ngModel.$parsers.push(function(value) {
return value == 'true' || value == true;
});
ngModel.$formatters.push(function(value) {
return value && value != 'false' ? 'true' : 'false';
});
}
};
});
The priority is set specifically so that it is done prior to any other directives (that usually don't have a priority set, and defaults to 0)
For example, I use this directive (for a true/false selection) with my selectpicker directive that wraps my select elements in the selectpicker bootstrap plugin.
Edit:
The caveat here, which I forgot to mention, is that your html values need to be string values. What the directive does is translates between the view and the model, keeping the model value in boolean and your view in string format:
%select.selectpicker{ ng: { model: 'modelForm.listed' }, selectpicker: '{ }', boolean: true }
%option{ value: 'true' } Listed
%option{ value: 'false' } Unlisted
This will work too. Just force the value to be boolean by putting an angular expression in for the value.
<select class="span9" ng-model="proposal.formalStoryboard">
<option value="{{false}}"
ng-selected="proposal.formalStoryboard === false">
Not Included
</option>
<option value="{{true}}"
ng-selected="proposal.formalStoryboard === true">
Included
</option>
</select>
I created sample for you, please check this out.
Is it what you want to use model to drive the ui binding?
<div ng-app ng-controller="Ctrl">
<select class="span9" ng-model="proposal.formalStoryboard">
<option value="false">Not Included</option>
<option value="true">Included</option>
</select>
<button ng-click="changeValue();">Click</button>
<div>
function Ctrl($scope) {
$scope.proposal = {};
$scope.proposal.formalStoryboard = true;
$scope.changeValue = function () {
$scope.proposal.formalStoryboard = !$scope.proposal.formalStoryboard;
console.log($scope.proposal.formalStoryboard);
}
}
I had very little success with this frustrating issue. My solution, while not too elegant since it's an additional line of code, solved it every time. This may not work in every application.
$scope.myObject.myBooleanProperty = $scope.myObject.myBooleanProperty.toString();
Turning it into a "real" string before trying to rebind it to the model displayed on the page allowed it to correctly select the value.
Angular does a strict comparsion between the Value bind to ng-model and the Values in the given Options. The Values given in the initial Question are the Strings "false" and "true".
If the Value of ng-model is of Type bool and defined like {"Value":false}, Angulars strict === comparsion between string and bool does never match so the select-box is empty.
The real Problem is- if you select a Value, the Type changed from bool to string ({"Value":false} --> {"Value":"false"})can cause errors if posted back.
The best Solution for both issues for me was the one of Thiago Passos in this Post.
(https://stackoverflow.com/a/31636437/6319374)
<script type='text/javascript'>
function MyCntrl($scope) {<!--from ww w . j a v a 2s. c om-->
$scope.mybool = true;
}
</script>
</head>
<body>
<div ng-app="">
<div ng-controller="MyCntrl">
<select ng-model="mybool">
<option value="false">Not Included</option>
<option value="true">Included</option>
</select>
<p>
Currently selected: {{ mybool }}
</p>
</div>
</div>
</body>
</html>

Categories

Resources