AngularJS checkbox dynamic ng-true-value expression - javascript

I'm trying to build a calculator for daycare prices in Angular.
Every location in the company franchise has separate prices for every day. So my thinking was to build a form, with first a select that allows you to select the location, then a series of checkboxes for the days.
I'm having trouble with ng-true-value in the checkboxes selecting the correct prices from my json file.
UPDATE: Added Plunkr: http://plnkr.co/edit/MDmrqaH1VzLBzjd5eHgT?p=preview
Consider this code:
<p class="kind_section">Choose location</p>
<select ng-model="formData.location" ng-options="location.title for location in data.bso"></select>
<p class="kind_section">Select days</p>
<input type="checkbox" ng-model="location.day.mon" ng-change="calculatePrice()" ng-true-value="{{data.bso[formData.location.ID].prices.monday}}" ng-false-value="0">Ma
<input type="checkbox" ng-model="location.day.tue" ng-change="calculatePrice()" ng-true-value="{{data.bso[formData.location.ID].prices.tuesday}}" ng-false-value="0">Di<br />
<input type="checkbox" ng-model="location.day.wed" ng-change="calculatePrice()" ng-true-value="{{data.bso[formData.location.ID].prices.wednesday}}" ng-false-value="0">Wo
<input type="checkbox" ng-model="location.day.thu" ng-change="calculatePrice()" ng-true-value="{{data.bso[formData.location.ID].prices.thursday}}" ng-false-value="0">Do<br />
<input type="checkbox" ng-model="location.day.fri" ng-change="calculatePrice()" ng-true-value="{{data.bso[formData.location.ID].prices.friday}}" ng-false-value="0">Vr
First the select sets formData with a location ID, then I want to use this ID to select the day prices for the matching location and set those to ng-true-value.
I'm using ng-true-value="{{data.bso[formData.location.ID].prices.monday}}" for this. This doesn't work.
When I set the ID manually like ng-true-value="{{data.bso[0].prices.monday}}" it does work. Why is the result of the select not being picked up by ng-true-value?
This is my json file:
$scope.data = {
"bso": [
{
"ID": 0,
"title": "Locatie 1",
"prices": {
"monday": 130,
"tuesday": 130,
"wednesday": 200,
"thursday":130,
"friday": 130
}
},
{
"ID": 1,
"title": "Locatie 2",
"prices": {
"monday": 430,
"tuesday": 530,
"wednesday": 600,
"thursday":990,
"friday": 730
}
}
]
};

It seems ng-true-value does not accept non-constant expressions. From the docs(v1.3.0):
Some attributes used in conjunction with ngModel (such as ngTrueValue or ngFalseValue) will only accept constant expressions.
Examples using constant expressions include:
<input type="checkbox" ng-model="..." ng-true-value="'truthyValue'">
<input type="checkbox" ng-model="..." ng-false-value="0">
Examples of non-constant expressions include:
<input type="checkbox" ng-model="..." ng-true-value="someValue">
<input type="checkbox" ng-model="..." ng-false-value="{foo: someScopeValue}">
An ideal workaround probably would be calling a Controller method on ng-click or ng-change inside which you can analyse all the checkboxes for truthy or non-truthy values.

Another approach is to delay the creation of the checkbox until the value is ready (on scope or whatever).
In my case I was loading a value via http that wasn't on the scope when the checkbox was created. So I just wrapped it in an ng-if.
<div class="checkbox" ng-if="viewData.conditionId != undefined">
<label>
<input type="checkbox" ng-true-value="{{'\''+ viewData.conditionId + '\''}}" ng-false-value="undefined" ng-model="model.conditionId" required />
I agree
</label>
</div>
Which worked perfectly for my scenario. Yours is a bit different but the same principal should apply - delay creation of the checkbox until you know the value being bound is there.
And yes the stupid quotation marks seem to be necessary.

Expression in the ng-true-value will be evaluated only once, so it won't be dynamic.
One alternative approach is to calculate the values in ng-change callback instead.
Please see my fork http://plnkr.co/edit/9zYS3OZ0sSkXX9rHwcgv?p=preview for the full example.
In html:
<input type="checkbox" ng-model="selectedDays.monday" ng-change="calculatePrice()" /> Mon
<input type="checkbox" ng-model="selectedDays.tuesday" ng-change="calculatePrice()" /> Tue <br />
<input type="checkbox" ng-model="selectedDays.wednesday" ng-change="calculatePrice()" /> Wed
<input type="checkbox" ng-model="selectedDays.thursday" ng-change="calculatePrice()" /> Thu <br />
<input type="checkbox" ng-model="selectedDays.friday" ng-change="calculatePrice()" /> Fri
and in controller:
$scope.calculatePrice = function(){
$scope.formData.location.day = {};
angular.forEach($scope.selectedDays, function (selected, day) {
if (selected) {
$scope.formData.location.day[day.slice(0, 3)] = $scope.data.bso[$scope.formData.location.ID].prices[day];
}
});
}
$scope.selectedDays = {};

Related

Setting a checkbox as checked with Vue.js

I have been googling and playing with every combination I know but I cannot get my checkboxes to be initialised as checked.
Example:
<ul class="object administrator-checkbox-list">
<li v-for="module in modules">
<label v-bind:for="module.id">
<input type="checkbox" v-model="form.modules" v-bind:value="module.id" v-bind:id="module.id">
<span>#{{ module.name }}</span>
</label>
</li>
</ul>
An example of the modules data:
[
{
"id": 1,
"name": "Business",
"checked": true
},
{
"id": 2,
"name": "Business 2",
"checked": false
},
]
What can I do to initially set the checked status of the checkboxes?
To set the state of the checkbox, you need to bind the v-model to a value. The checkbox will be checked if the value is truthy. In this case, you are iterating over modules and each module has a checked property.
The following code will bind the checkbox to that property:
<input type="checkbox" v-model="module.checked" v-bind:id="module.id">
If you'd like to know more about how v-model works in this situation, here's a link to the documentation about Form Input Binding.
Let's say you want to pass a prop to a child component and that prop is a boolean that will determine if the checkbox is checked or not, then you have to pass the boolean value to the v-bind:checked="booleanValue" or the shorter way :checked="booleanValue", for example:
<input
id="checkbox"
type="checkbox"
:value="checkboxVal"
:checked="booleanValue"
v-on:input="checkboxVal = $event.target.value"
/>
That should work and the checkbox will display the checkbox with it's current boolean state (if true checked, if not unchecked).
In the v-model the value of the property might not be a strict boolean value and the checkbox might not 'recognise' the value as checked/unchecked. There is a neat feature in VueJS to make the conversion to true or false:
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no"
>
I had similar requirements but I didn't want to use v-model to have the state in the parent component. Then I got this to work:
<input
type="checkbox"
:checked="checked"
#input="checked = $event.target.checked"
/>
To pass down the value from the parent, I made a small change on this and it works.
<input
type="checkbox"
:checked="aPropFrom"
#input="$emit('update:aPropFrom', $event.target.checked)"
/>
I experienced this issue and couldn't figure out a fix for a few hours, until I realised I had incorrectly prevented native events from occurring with:
<input type="checkbox" #click.prevent="toggleConfirmedStatus(render.uuid)"
:checked="confirmed.indexOf(render.uuid) > -1"
:value="render.uuid"
/>
removing the .prevent from the #click handler fixed my issue.
<input v-if = "module.checked == true" checked type="checkbox" >
<input v-else-if = "module.checked == false" type="checkbox" >
I have solved this with use of v-if and v-else-if
I use both hidden and checkbox type input to ensure either 0 or 1 submitted to the form. Make sure the field name are the same so only one input will be sent to the server.
<input type="hidden" :name="fieldName" value="0">
<input type="checkbox" :name="fieldName" value="1" :checked="checked">
In my case I had an simple boolean type, so What I did is:
in my html:
<input type="checkbox" :checked="article.is_public" :value="article.is_public" #change="updateIsPublic($event.target.checked)">
methods: {
updateIsPublic (e) {
this.$store.commit('articles/UPDATE_IS_PUBLIC', e);
},
}
Store
UPDATE_IS_PUBLIC(state, value) {
state.article.is_public = value;
}
for bootstrap vue
if value is a "1" then value="1" and for "0" unchecked-value="0"

Using querySelector to read 2 values from radio button

Hello how can i use the queryselector to read two values from a radio button and store the values in array in javascript. Example of the code below is:
<input type="radio" name="one" value="correct" class="firstRow"> Option 1 Mark 1: $650
<input type="radio" name="two" value="incorrect" class="secondRow"> Option 1 Mark 2: Twitter<br>
<input type="radio" name="one" value="incorrect" class="firstRow"> Option 2 Mark 1:$550
<input type="radio" name="two" value="incorrect" class="secondRow"> Option 2 Mark 2:Google<br>
<input type="radio" name="one" value="incorrect" class="firstRow"> Option 3 Mark 1:$650
<input type="radio" name="two" value="correct" class="secondRow"> Option 3 Mark 2:$650<br>
<!--button -->
<input type="button" value="Submit & Next Question" onclick="getAnswer3(this.form)" class="firstRow">
<input type="button" value="Cancel & Clear Selection" onclick="clearOptions(this.form)">
Javascript my idea:
function getAnswer3(form) {
var result = [];
//this only reads one value but i need to read 2 values..
var checked = form.querySelector("input[type=radio]:checked");
if(!checked) {
alert('Please select 2 answers..');
}
else{
//reads the values
}
//stores the values in the array..
}
You need form.querySelectorAll("input[type=radio]:checked");
Keep in mind that what comes back from querySelectorAll is not really an array, and so doesn't have any of the particularly fun and easy helper methods that typical arrays do.
It does have a length, though.
if checked is not going to be helpful, though.
You're always going to get a NodeList back.
The list might have length === 0, but it'll still be a list (and thus still pass the check to see if it exists). Check that length is < 2, instead.

How to build an SQL query from HTML checkboxes?

I need to create a query builder for SQL, where you can choose query constraints via HTML checkboxes. Each checkbox has a name,used for a column name (e.g ActorName), and a value for the column value (like Tom Hanks).
I'm having trouble deciding what is the best way to do this. I've tried adding/removing to a JavaScript object, and then iterating through each key-value pair, i.e each ActorName, each DirectorName, and append them to the WHERE constraint in SQL, but as the checkbox names are not unique, i.e there are many Actors, Genres etc, it complicates things. Right now, I'm using this method:
https://jsfiddle.net/Lompm0ew/5/
On checkbox checked, add the checkbox's name and value to a JS object, with the ActorName as the object key (as this will always be unique), and the checkbox name as the object value. I have a feeling this is bad practice, and I'm sure there is a better way to achieve my goal, but I'm out of ideas.
can anyone recommend a better method of building a query from checkboxes?
You can use "serialize" for get and send data with Ajax
First, add a form balsise in your HTML code
Example :
<form>
<div id="checkboxes">
<label>
<input type="checkbox" value="Tom Hanks" name="actorName[]">Tom Hanks</label>
<label>
<input type="checkbox" value="Tim Allen" name="actorName[]">Tim Allen</label>
<label>
<input type="checkbox" value="Don Rickles" name="actorName[]">Don Rickles</label>
<label>
<input type="checkbox" value="Jim Varney" name="actorName[]">Jim Varney</label>
<label>
<input type="checkbox" value="Wallace Shawn" name="actorName[]">Wallace Shawn</label>
<label>
<input type="checkbox" value="Fantasy" name="genreName[]">Fantasy</label>
<label>
<input type="checkbox" value="Comedy" name="genreName[]">Comedy</label>
<label>
<input type="checkbox" value="Children" name="genreName[]">Children</label>
<label>
<input type="checkbox" value="Animation" name="genreName[]">Animation</label>
<label>
<input type="checkbox" value="Adventure" name="genreName[]">Adventure</label>
<label>
<input type="checkbox" value="USA" name="countryName">USA</label>
</div>
</form>
Your javascript :
jQuery(document).ready(function($){
$(':checkbox').change(function() {
sendData();
});
})
function sendData () {
var $form = $('form');
$.ajax({
url : 'ajax.php',
data: $form.serialize(),
async : false,
success : function(response){
console.log(response);
}
});
}
Your ajax.php
<?php
var_dump($_REQUEST);
Show :
array(2) {
["actorName"]=>
array(3) {
[0]=>
string(9) "Tim Allen"
[1]=>
string(10) "Jim Varney"
[2]=>
string(13) "Wallace Shawn"
}
["genreName"]=>
array(1) {
[0]=>
string(9) "Animation"
}
}
Each time you click on checkbox, you send data for ajax.php. So, you can make the query server side
Edit : Sorry I've forgot : You can rename your checkbox name for send a array
<label>
<input type="checkbox" value="Tom Hanks" name="actorName[]">Tom Hanks</label>
<label>
<input type="checkbox" value="Tim Allen" name="actorName[]">Tim Allen</label>
<label>

ng-repeat multiple radiobutton groups with "checked" property -- only last group gets checked

See jsBin
For each item in an array, I'm trying to create a list of 6 radio buttons, where the fourth item is initially the checked value in all of them. When this renders, however, only the fourth item of the last group of radio buttons is checked. The name="checkpoint{{$index}}" is working, as the groups are individually selectable, just the initial setting of the values is not.
<table>
<tbody>
<tr ng-repeat="checkpoint in checkpoints">
<td>
<input type="radio" name="checkpoint{{$index}}" />
<input type="radio" name="checkpoint{{$index}}" />
<input type="radio" name="checkpoint{{$index}}" />
<input type="radio" name="checkpoint{{$index}}" checked /> <!-- This checked property is only working on the last set of radio buttons -->
<input type="radio" name="checkpoint{{$index}}" />
<input type="radio" name="checkpoint{{$index}}" />
checkpoint{{$index}}
</td>
</tr>
</tbody>
</table>
And the javascript for that:
var app = angular.module('app', []).controller('MyController', function($scope) {
$scope.checkpoints = [
{
name: "one"
},
{
name: "two"
},
{
name: "three"
},
{
name: "four"
}
];
});
Try using
ng-checked="true"
Instead of the native checked.
Edit:
Documentation for ngChecked for reference.
https://docs.angularjs.org/api/ng/directive/ngChecked

Knockoutjs checkbox changed event

I have some checkboxes bound to an array in my model. This works great, when you check a box the array is updated accordingly.
However when the value has changed i wish to call a method on my model to filter the results given the new values. I have tried hooking up the change event but this seems to have the values prior to the change rather than after the change.
I have illustrated my issue in a jsfiddle http://jsfiddle.net/LpKSe/ which might make this make more sense.
For completeness my code is repeated here.
JS
function SizeModel() {
var self = this;
self.sizes = ko.observableArray(["small", "medium", "large"]);
self.sizes2 = ko.observableArray(["small", "medium", "large"]);
self.getResults = function(e) {
alert(self.sizes());
};
self.getResults2 = function(e) {
alert(self.sizes2());
};
}
$(document).ready(function() {
sizeModel = new SizeModel();
ko.applyBindings(sizeModel);
});​
Html
<h3>Size
<input type="checkbox" value="small" data-bind=" checked: sizes, event:{change: getResults}"/>
<span class='headertext'>Small</span>
<input type="checkbox" value="medium" data-bind=" checked: sizes, event:{change: getResults}" />
<span class='headertext'>Medium</span>
<input type="checkbox" value="large" data-bind=" checked: sizes, event:{change: getResults}" />
<span class='headertext'>Large</span>
</h3>
<h3>Size
<input type="checkbox" value="small" data-bind=" checked: sizes2, event:{click: getResults2}"/>
<span class='headertext'>Small</span>
<input type="checkbox" value="medium" data-bind=" checked: sizes2, event:{click: getResults2}" />
<span class='headertext'>Medium</span>
<input type="checkbox" value="large" data-bind=" checked: sizes2, event:{click: getResults2}" />
<span class='headertext'>Large</span>
</h3>
You don't need the change event. If you subscribe to the observableArray you will be notified when it changes, and be passed the updated array: http://jsfiddle.net/jearles/LpKSe/53/
function SizeModel() {
var self = this;
self.sizes = ko.observableArray(["3", "2", "1"]);
self.sizes.subscribe(function(updated) {
alert(updated);
});
}
In your fiddle you're missing commas in your data-bind-s, here's a fixed example: http://jsfiddle.net/4aau4/1/
Re the problem - it might be either a KnockoutJS-related problem (i.e. it updates the observableArray after the change event is fired), or something similar to what I stucked on some time ago: Checkboxes are being checked before click handler is even called
EDIT:
What a tough Sunday, I think I'm still not awake :)
Take a look at this snippet: http://jsfiddle.net/4aau4/2/ - it looks like DOM is properly updated and it's ko.observableArray that lags behind. ($('input:checked').length says how many checkboxes are actualy checked).

Categories