Angular, boolean value in a select box - javascript

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>

Related

VueJs bind boolean values to dropdown

I have a dropdown with two options: "True" and "False", when selected, I want the form to save the selected value as a boolean.
So if I check the form value when the user has selected "True", I want the value to be true as a boolean.
<select v-model="selected">
<option :value="null">Pick a value</option>
<option v-for="val in options">{{val}}</option>
</select>
...
data() {
return {
selected: null,
options: ["true", "false"]
}
Here is a fiddle of what I am attempting:
https://jsfiddle.net/q0nk9h32/5/
How can I output the selected values in their boolean form?
Bonus question: Instead of having the options variable, is it valid syntax / good practice, to do:
v-for="val in ["true", "false"]" ?
It seems overkill to have a variable for this (but it fails in fiddle when I try using an array directly). Thanks!
You can bind a value to each <option> using :value.
https://v2.vuejs.org/v2/guide/forms.html#Select-Options
new Vue({
el: '#app',
data() {
return {
selected: null
}
}
});
<script src="https://unpkg.com/vue"></script>
<div id="app">
<select v-model="selected">
<option :value="null">Pick a value</option>
<option v-for="val in [true, false]" :value="val">{{val}}!!!</option>
</select>
<p>
Selected is the {{ typeof selected }}: {{ selected }}
</p>
</div>
You can write the array for a v-for inline if you want. In your original example it wouldn't have worked because you included double quotes around your strings but were already using double quotes around the attribute.
You've got lots of options for rendering the text as True and False for these values...
If you just have two values, true and false, I'd be inclined to drop the v-for altogether and just write them separately.
<option :value="null">Pick a value</option>
<option :value="true">True</option>
<option :value="false">False</option>
Alternative ways of formatting the text would be to use a filter or method. So that's:
<option v-for="val in [true, false]" :value="val">{{ val | filter }}</option>
or
<option v-for="val in [true, false]" :value="val">{{ method(val) }}</option>
For a filter you'd define it in your component's filters section, for a method it'd be in your methods. Either way the function just needs to convert the boolean value to a string and then uppercase the first letter.
// Obviously you wouldn't call it 'method'...
method (value) {
const str = String(value);
return str.charAt(0).toUpperCase() + str.slice(1);
}
That said, given there are only two possible options, there are all sorts of other ways to do it. e.g.:
<option v-for="val in [true, false]" :value="val">{{ val ? 'True' : 'False' }}</option>
One option would be to create a computed property that just returns this.selected === 'true'.

AngularJS not binding to numeric value in select list

I have an existing select tag with existing option tags, one marked "selected", for example:
<div class="form-group">
<label class="control-label">Test</label>
<select ng-model="vm.testNumber">
<option>Choose...</option>
<option value="1">one</option>
<option value="2">two</option>
<option value="3" selected>three</option>
</select>
<p class="help-block">{{vm.testNumber}}</p>
</div>
Angular is binding to the model correctly and spits out "3" in the help block when the page loads, but option 3 is not selected. It binds and shows 3 as selected if I use text for the value attributes on each option, but not when it's a numerical value. Instead it inserts an option at the top of the select list:
<option value="? number:3 ?"></option>
What am I doing wrong?
From Angular DOC
Note that the value of a select directive used without ngOptions is always a string. When the model needs to be bound to a non-string value, you must either explicitly convert it or use ngOptions to specify the set of options. This is because an option element can only be bound to string values at present.
If you change your code as like as below code snippet, you don't need to do any explicit string conversions.
<select ng-model="vm.testNumber" ng-options="item.value as item.label for item in [{label: 'one', value: 1}, {label: 'two', value: 2}]">
<option value="">Choose...</option>
</select>
Turns out you need to add a directive to make this work correctly. #codeninja.sj's answer ends up replacing 'one' with 1, 'two' with 2, etc. In the documention, the last example has this directive, convert-to-number
angular.module('app').directive('convertToNumber', function () {
return {
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
ngModel.$parsers.push(function (val) {
return parseInt(val, 10);
});
ngModel.$formatters.push(function (val) {
return '' + val;
});
}
};
});
None of the other examples in the documentation worked for me.
Update #codeninja.sj's updated answer does work, however, figure this directive will cut down on magic strings in my code.

Angularjs Dropdown won't hold value after refresh

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?

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.

jQuery validation on select box not working

I am using jQuery validation plugin for client side validation, but my validation does not work on my select box.
HTML
<select id="select" class="required">
<option value="-1">Choose</option>
<option value="child">test2</option>
</select>
JavaScript
$("#formid").validate({
select: {
required: function(element) {
if ($("#select").val() == '-1') {
return false;
} else {
return true;
}
}
}
});
How do I get this working?
A simple way to fix this problem is to give the non valid option the value of "". Then simply call validate on your form and it will not submit when "Choose" is selected.
HTML
<form id="formid">
<select name="select" class="required">
<option value="">Choose</option>
<option value="child">test2</option>
</select>
<input type="submit" />
</form>​
JavaScript
$("#formid").validate(); ​
Demo
Although this probably works with some of the aforementioned methods,if you're looking to use a custom validation function, you should use addMethod as documented here: http://docs.jquery.com/Plugins/Validation/Validator/addMethod
So you would first add the method through something like
$.validator.addMethod("requiredSelect", function(element) {
return ( $("#select").val() !='-1' );
}, "You must select an option.");
Then simply assign the validator with
$("#formid").validate({
rules: {
select: { requiredSelect : true }
}
});
For some reason no solution provided worked in my case, it boiled down to jQuery Validate calling the "optional" check on the value of the drop down, which that called the !required rule.
When the select box selected an empty value, the required showed "false" which inverted meant it was always optional when the required failed, so it never ran the required rule.
I overwrote the optional function with the below, which returned "False" on optional if it was a required item:
// Get Select to work
$.validator.prototype.optional = function (element) {
var val = this.elementValue(element);
// Custom logic to get Select to show validate when value is empty
if (element.nodeName.toLowerCase() === "select") {
if (element.hasAttribute("data-val-required") || element.hasAttribute("required")) {
return false;
}
}
return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch";
};
instead of:
$("#select").val()
try:
$("#select :selected").val()
$("#select").val() returns all the option values instead of the selected one.
Here, my assumption is that you want to check if the user has chosen the option -1 when the control report-crime is validated.
by default
<option value="">Choose</option>
works with
required: true
There is missing name attribute in your select element.
In my case that was the issue since the jQuery Validatation Plugin looks for the name not id while validating.

Categories

Resources