checkbox array in knockout being all checked on click - javascript

I am having an issue with knockout,
when i check a box, they're all being checked...
this is what I have:
_Categories_List has all the items,
and
My_categories is the empty list where I want to have each id added
this is the code:
<!-- ko foreach: _Categories_List -->
<input type="checkbox" data-bind="attr: {value: $data}, checked: $root.My_categories" />
<span data-bind="text: CODE"></span><br />
<!-- /ko -->
and this is the JS part of the code (i cant really change this as to how the code is in the documentation because i'm building off someone else's work and should use the same code - referring to the mapping.fromJS):
var Poi = new Object();
Poi.My_categories = [];
var _Poi = ko.mapping.fromJS(Poi);
var Categories_List = [];
var _Categories_List = ko.mapping.fromJS(Categories_List);
$(document).ready
(
function () {
ko.applyBindings(_Poi);
// here there's an ajax function to load the categories returned in i_Input.My_Result, then:
ko.mapping.fromJS(i_Input.My_Result, _Categories_List);
}
);
this is what the object loaded from ajax looks like:
{"My_Result":[
{"CODE":"chalet","DEF_POIS_CATEGORY_ID":2,"DESCRIPTION":"chalet","ENTRY_DATE":"2012-10-10","ENTRY_USER_ID":2,"OWNER_ID":1},
{"CODE":"vila","DEF_POIS_CATEGORY_ID":3,"DESCRIPTION":"villa","ENTRY_DATE":"2012-10-10","ENTRY_USER_ID":2,"OWNER_ID":1}
]}

The checked binding works off of the value of the input element. In your code, you are setting the value equal to an object, which turns into [object Object], so both of your inputs have the same value, which is why checking one toggles both.
So, you would want to set your value equal to a key on the object like your CODE property. If necessary, then you can use a computed observable to represent the actual objects.
Here is a sample: http://jsfiddle.net/rniemeyer/7n9gR/

Related

ng-repeat not updating information after $scope was updated

I have an ng-repeat which creates a form with some starting data. Then the user is free to modify said data and the changes should appear in the form. Before that, the user submitted data are sanitized by another function, which is called by an ng-click on a button.
Everything works well under the hood (I checked my $scope.some_array, from which ng-repeat takes the data and the new data is in the right place) but nothing happens on the page.
The element:
<li ng-repeat="field in some_array" id="field-{{$index}}">
<div class="{{field.field_color}}">
<button type="button" ng-click="save_field($index)">done</button>
{{field.nice_name}}
</div>
<div id="field-input-{{$index}}">
<input type="text" id="{{field.tag}}" value="{{field.content}}">
<label for="{{field.tag}}">{{field.nice_name}}</label>
</div>
</li>
save_field code:
$scope.save_field = function (index) {
console.log($scope.some_array[index]["content"])
var value = $("#field-" + index).children("div").children("input").val()
var name = $scope.some_array[index]["name"]
var clean_value = my_clean(value)
if (norm_value === "") {
return
}
$scope.some_array[index]["content"] = clean_value
console.log($scope.some_array[index]["content"])
}
On the console I see:
10.03.16
10/03/16
Which is right, but in the form I only see 10.03.16. I already tried putting $timeout(function(){$scope.$apply()}) as the last line of my function, but the output is still the same.
You shouldn't use input like this if you want to bind a variable to it. Digest loop will refresh the value but it will not be updated visibly because this is not html native behavior.
Use ng-model instead, it will update view value of the input as expected:
<input type="text" id="{{field.tag}}" ng-model="field.content">
Also using ng-model your variable will be updated when user modify the input, so you can retrieve it to do some treatments much more easily in save_field function, without jQuery:
$scope.save_field = function (index) {
if (norm_value === "") {
return;
}
$scope.some_array[index]["content"] = my_clean($scope.some_array[index]["content"]);
};
More infos: https://docs.angularjs.org/api/ng/directive/ngModel

Changing input box also need to find check box checked or not in JS

I have input box along with checkbox in table <td> like below,
<td>
<input class="Comment" type="text" data-db="comment" data-id="{{uid}}"/>
<input type="checkbox" id="summary" title="Check to set as Summary" />
</td>
Based on check box only the content of input box will be stored in DB.
In the JS file, I tried like
var updateComment = function( eventData )
{
var target = eventData.target;
var dbColumn = $(target).attr('data-db');
var api = $('#api').val();
var newValue = $(target).val();
var rowID = $(target).attr('data-id');
var summary = $('#summary').is(':checked');
params = { "function":"updatecomments", "id": rowID, "summary": summary };
params[dbColumn] = newValue;
jQuery.post( api, params);
};
$('.Comment').change(updateComment);
But the var summary always returning false.
I tried so many ways prop('checked'),(#summary:checked).val() all are returning false only.
How to solve this problem?
Looks like you have multiple rows of checkboxes + input fields in your table. So doing $('#summary').is(':checked') will return the value of first matching element since id in a DOM should be unique.
So, modify your code like this:
<td>
<input class="Comment" type="text" data-db="comment" data-id="{{uid}}"/>
<input type="checkbox" class="summary" title="Check to set as Summary" />
</td>
And, instead of $('#summary').is(':checked'); you can write like this:
var summary = $(target).parent().find(".summary").is(':checked');
By doing this, we are making sure that we are checking the value of checkbox with the selected input field only.
Update: For listening on both the conditions i.e. when when checking checkbox first and then typing input box and when first typing input box and then checked:
Register the change event for checkbox:
// Whenever user changes any checkbox
$(".summary").change(function() {
// Trigger the "change" event in sibling input element
$(this).parent().find(".Comment").trigger("change");
});
You have missed the jQuery function --> $
$('#summary').is(':checked')
('#summary') is a string wrapped in Parentheses. $ is an alias for the jQuery function, so $('#summary') is calling jquery with the selector as a parameter.
My experience is that attr() always works.
var chk_summary = false;
var summary = $("#summary").attr('checked');
if ( summary === 'checked') {
chk_summary = true;
}
and then use value chk_summary
Change all the occurrences of
eventData
To
event
because event object has a property named target.
And you should have to know change event fires when you leave your target element. So, if checkbox is checked first then put some text in the input text and apply a blur on it, the it will produce true.
Use like this
var summary = $('#summary').prop('checked');
The prop() method gets the property value
For more details, please visit below link.
https://stackoverflow.com/a/6170016/2240375

How to check checkbox based on array value in knockout js

I'm doing knockout js. I have an array list coming from the database by making an ajax call and saving all the values in knockout observable array.
I'm looping through the array. Based on a value I want to check or uncheck the checkbox. Below is how I'm doing but this does not seems to be working. I can see values for roleid exists in the array but the checkbox is not checked if the value of roleid is true. What am i doing wrong here.
<tbody data-bind="foreach:$root.test">
<tr>
<div><input type="checkbox" value="1" data-bind="checked: roleid == 1"/></div>
</tr>
</tbody>
I think roleid needs to be observable. And then you can use
roleid() === 1
or
roleid() === true
whichever is appropriate for your case.
this will work if roleid is an observable and is set to a string value.
knockout "checked" compares only string values vs string values, so the value inside value="1" is considered a string.
so your checkbox will be checked if roleid is setup like this
viewModel.roleid = ko.observable("1");
You can use checkedValue binding and can assign the observableArray to checked binding.
From documentation
If your binding also includes checkedValue, this defines the value used by the checked binding instead of the element’s value attribute. This is useful if you want the value to be something other than a string (such as an integer or object), or you want the value set dynamically.
Here is the javascript code:
function viewModel()
{
var self = this;
//the array list which you can get from the server
self.items = ko.observableArray([
{ item: '1' },
{ item: '2' },
{ item: '3' },
{ item: '4' }
]);
//the array of items which you want to be checked
self.chosenItems = ko.observableArray(
[
self.items()[1],
self.items()[3]
]
);
}
Html code
<div data-bind="foreach: items">
<input type="checkbox"
data-bind="checkedValue: $data, checked: $root.chosenItems" />
<span data-bind="text: item"></span><br />
</div>
And here is the Js fiddle demonstrating the use.

Grails richui autocomplete passing object to function or updating object ID

I've got a table with a load of auto complete boxes in it which look like so...
<richui:autoComplete style="width:500px" name="objSelect[${newRow-1}].id" value= "" action="${createLinkTo('dir': 'object/searchAJAX')}" forceSelection = "true" maxResultsDisplayed="20" minQueryLength ="3" onItemSelect="updateHiddenInput(id,${newRow-1})" />
I've got it to call a function called updateHiddenInput when a user selects a value passing in the id selected as well as the row the autocomplete is on (this function then updates a hidden field in the same row, using the values passed in, with the ID). The function looks like so: -
function updateHiddenInput(id, num){
var objID = "objectID[" + num + "].id";
$(document.getElementById(objID)).val(id);
}
Everything works until I add a new row within my table, this pushes everything down one row and stops the autocomplete from updating the right rows hidden field (as its still referencing the old row).
Currently I have another piece of code that goes through and renames all the fields when a new row is inserted, but I have no idea how to update the autocomplete so that it passes through the right row number, anyone know how I can alter this?
The only other alternative I could think of would be to just pass through the object itself as well as the ID I can then locate the hidden based off the object, but I can't work out how to do this, any suggestions gratefully received! :S
I've tried changing
onItemSelect="updateHiddenInput(id,${newRow-1})"
to
onItemSelect="updateHiddenInput(id,this)"
Theoretically so I can just pass through the autocomplete object and from there just traverse the page to find the hidden field I want to update. However when I then attempt to use that object in my function, for example with something like: -
var mynumber = $(myobject).closest('td').find('input').val();
I always get an "undefined" returned when I try to alert back the value...
If I just put in an alert(myobject) in the function it returns AutoComplete instance0 autoLook[0].id but if I've inserted new lines the id value doesn't change (i.e the objects id is now autoLook[3].id but it still shows [0], which I think could be part of the problem but I've got now idea how I can update this value...
I notice when looking in firebug at the html there is a /script linked to the autocomplete which could be the problem as this doesn't get updated when new lines are added and I can see multiple references to the old/original id value (see below) so maybe the passing through of this isn't passing the current objects values through...?
<script type="text/javascript">
var autoCompleteDataSource = new YAHOO.util.XHRDataSource("/Framework/object/searchAJAX");
autoCompleteDataSource.responseType = YAHOO.util.XHRDataSource.TYPE_XML;
autoCompleteDataSource.responseSchema = {
resultNode : "result",
fields : [
{ key: "name" },
{ key: "id" }
]
};
;
autoComplete = new YAHOO.widget.AutoComplete('autoLook[0].id','ad186a42e45d14d5cde8281514f877e42', autoCompleteDataSource);
autoComplete.queryDelay = 0;
autoComplete.prehighlightClassName = 'yui-ac-prehighlight';
autoComplete.useShadow = false;
autoComplete.minQueryLength = 3;
autoComplete.typeAhead = false;
autoComplete.forceSelection = true;
autoComplete.maxResultsDisplayed = 20;
autoComplete.shadow = false;
var itemSelectHandler = function(sType, args) {
var autoCompleteInstance = args[0];
var selectedItem = args[1];
var data = args[2];
var id = data[1];
updateHiddenInput(id,this) };
autoComplete.itemSelectEvent.subscribe(itemSelectHandler);
</script>
My thanks so far to user1690588 for all his help thus far! :)
On further digging I'm convinced that my issues is down to the line autoComplete = new YAHOO.widget.AutoComplete('autoLook[0].id','a5b57b386a2d1c283068b796834050186', autoCompleteDataSource); specifically the part where its inputting autoLook[].id and if I could change this I'd then be ok, but this line is auto generated and I've got no idea how to update it, anyone have any similar experience?
I have not much idea about your gsp page but I tried it on my side:
My gsp:
<!DOCTYPE html>
<html>
<head>
<resource:autoComplete skin="default"/>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
var counter = ${list.size()};
function asd() {
jQuery.ajax({
url: " ${createLink(controller: 'oauthCallBack', action: 'testAuto')}",
data: "idx=" + counter++,
success: function (data) {
jQuery("#tableId").append("<tr><td>" + data + "</td></tr>");
}
});
}
function updateHiddenInput(id, tg) {
jQuery(tg).val(id);
}
</script>
</head>
<body>
<g:form>
<table id="tableId">
<g:each in="${list}" var="vr" status="idx">
<tr>
<td>
<richui:autoComplete name="name" id="uniqueId${idx}" action="${createLinkTo('dir': 'oauthCallBack/test')}" onItemSelect="updateHiddenInput(id, someId${idx})"/>
<g:hiddenField name="someName" id="someId${idx}" value=""/>
</td>
</tr>
</g:each>
</table>
</g:form>
<button onclick="asd()">Add</button>
</body>
</html>
My action:
def testAuto() {
render template: 'addNew', model: [idx: params.idx]
}
My template(addNew):
<richui:autoComplete name="name" id="uniqueId${idx}" action="${createLinkTo('dir': 'oauthCallBack/test')}"
onItemSelect="updateHiddenInput(id, someId${idx})"/>
<g:hiddenField name="someName" id="someId${idx}" value=""/>
Try this..,.
EDIT.....................................................................................
I supposed that you have successfully updated all the input field names. Then you can edit hidden field like:
View:
<tr class="dummyClass">
<td>
<richui:autoComplete name="name[${idx}]" id="uniqueId[${idx}]" action="${createLinkTo('dir': 'oauthCallBack/test')}" onItemSelect="updateHiddenInput(id, this)"/>
<g:hiddenField name="someName[${idx}]" id="someId[${idx}]" value=""/>
</td>
</tr>
jQuery:
function updateHiddenInput(id, tg) {
jQuery(tg._elTextbox).closest("tr.dummyClass").find("input[type=hidden]").val(id);
}
EDIT.....................................................................................
Why you need to change the 'id'? Changing name is sufficient to send values in order. And you can update the hidden field without id as above edit.
If you still need to change the id then you can change it by cloning the tr and then use regex. See this answer for full working example.

Radio Button List with Knockout.js

I'm trying to build a list of radio buttons with labels so that you can click the label to check the radio item. What I have works fine in Chrome, but not IE7. The HTML that get's spit out seems like it is correct, but when I click on the label, the corresponding radio button doesn't get selected.
JavaScript
function ReuqestType(id, name, billable) {
this.id = id;
this.name = name;
this.billable = billable;
}
function RequestViewModel() {
var self = this;
self.availableRequestTypes = [
new ReuqestType(1, "Travel", true),
new ReuqestType(2, "Bill Only", false),
new ReuqestType(3, "Both", true)
];
self.selectedRequestType = ko.observable();
}
HTML
Request Type
<br />
<!-- ko foreach: availableRequestTypes -->
<input type="radio" name="requestType" data-bind="value:id, attr: {'id': 'rt'+ id}" />
<label data-bind="text: name, attr:{'for':'rt'+id}">
</label>
<!-- /ko -->
What is the preferred way to do this?
This seems to be working correctly now as of the newest version of Knockout (2.1.0).
I'm unfamiliar with knockout.js, but you can normally bind label's to inputs just by making the label wrap around the input box too.
http://jsfiddle.net/QD2qC/
It looks like your HTML is fine. It could be a quirk of IE7 not being able to acknowledge clicks of labels that have been generated dynamically.
If you can't find a proper answer, you could always use this workaround:
$('label').on('click', function() {
var labelId = $(this).attr('for');
$('#' + labelId ).trigger('click');
});
I have changed it slightly by using on() instead of click() to account for these labels being generated dynamically.

Categories

Resources