How to get the elements selected of checkbox with knockout - javascript

<div id="title" data-bind="foreach: list">
<input type="checkbox" data-bind="attr:{id: $index,value: list.id}" class="k-checkbox">
<label class="k-checkbox-label" data-bind="attr:{for: $index},checked: myFunction(this),text: list.id"></label>
</div>
<span data-bind="text: elementsSelected"></span>
</div>
myFunction check if i selected the checkbox.
Into elementsSelected i would like to get the elements selected of 'list'.
Then i print this array into the span.

You can use ko.pureComputed to show the data based on your condition.
Here is an example:
var simpleListModel = function(id, item) {
var self = this;
self.id = ko.observable(id);
self.item = ko.observable(item);
self.isSelected = ko.observable(false);
self.printItem = ko.pureComputed(function() {
if(self.isSelected()) return self.id() + " " + self.item();
else return "";
}, this);
};
var masterVM = (function () {
var self = this;
self.lists = ko.observableArray();
for(var i = 0; i<5; i++) {
self.lists.push(new simpleListModel(i, "Item No. " + i));
}
})();
ko.applyBindings(masterVM);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="foreach: lists">
<div>
<span>Check to show the item: </span>
<input type="checkbox" data-bind="checked: isSelected" />
<span data-bind="text: printItem"></span>
</div>
</div>

Related

Find all inputs within a jquery object

I have a little problem with my template.
I would like to read in a template with jquery and then find all inputs within this object to manipulate them.
Unfortunately, the inputs are not returned.
I already use the function "checkInputs" in another place.
The target is not a template and it works without problems.
Here's my test code:
listOfTemplateInputs = checkInputs("#IncomingInformationsTemplate");
alert("Hidden: " + listOfTemplateInputs.Hidden.length + ", Fields: " + listOfTemplateInputs.Fields.length);
function checkInputs(target) {
var ListOfFields = [];
var ListOfCheckBoxes = [];
var ListOfHidden = [];
$(target + " input[type='text'], textarea, input[type='password']").each(function() {
var input = $(this);
ListOfFields.push(input);
});
$(target + " input[type='checkbox']").each(function() {
var input = $(this);
ListOfCheckBoxes.push(input);
});
$(target + " input[type='hidden']").each(function() {
var input = $(this);
ListOfHidden.push(input);
});
var inputList = {
Fields: ListOfFields,
CheckBoxes: ListOfCheckBoxes,
Hidden: ListOfHidden
};
return inputList;
}
And here is my template:
<script id="IncomingInformationsTemplate" type="text/html">
<tr class="">
<input autocomplete="off" name="IncomingInformations.Index" type="hidden" value="5eda7c21-9b4e-4eb5-b992-6a3ea16a46cd" />
<td>
<div>
<input type="hidden" name="country" value="Norway">
<input type="hidden" name="country2" value="Germany">
<input type="text" name="Name" value="Tom">
<input type="text" name="Name2" value="Lisa">
</div>
</td>
</tr>
</script>
The thing is that script tag does not parse the HTML and create a DOM out of it.
Its contents are just a string.
To be able to select from it, you should parse it (you can do it with jQuery) and select from the created (parsed) object.
Notice in the code below I first create a "mini (virtual) DOM" out of your template's text contents:
var miniDOM = $($(target).text());
And now use all selectors having it as context/root. E.g.
miniDOM.find("input[type='text'], textarea, input[type='password']").each(function() {
This finds the elements as you wanted.
listOfTemplateInputs = checkInputs("#IncomingInformationsTemplate");
alert("Hidden: " + listOfTemplateInputs.Hidden.length + ", Fields: " + listOfTemplateInputs.Fields.length);
function checkInputs(target) {
var miniDOM = $($(target).text());
var ListOfFields = [];
var ListOfCheckBoxes = [];
var ListOfHidden = [];
miniDOM.find("input[type='text'], textarea, input[type='password']").each(function() {
var input = $(this);
ListOfFields.push(input);
});
miniDOM.find("input[type='checkbox']").each(function() {
var input = $(this);
ListOfCheckBoxes.push(input);
});
miniDOM.find("input[type='hidden']").each(function() {
var input = $(this);
ListOfHidden.push(input);
});
var inputList = {
Fields: ListOfFields,
CheckBoxes: ListOfCheckBoxes,
Hidden: ListOfHidden
};
return inputList;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script id="IncomingInformationsTemplate" type="text/html">
<tr class="">
<input autocomplete="off" name="IncomingInformations.Index" type="hidden" value="5eda7c21-9b4e-4eb5-b992-6a3ea16a46cd" />
<td>
<div>
<input type="hidden" name="country" value="Norway">
<input type="hidden" name="country2" value="Germany">
<input type="text" name="Name" value="Tom">
<input type="text" name="Name2" value="Lisa">
</div>
</td>
</tr>
</script>
Of course, you could, alternatively, turn that script into any renderable element, like div or span, even if hidden, and you could query it with your original code:
listOfTemplateInputs = checkInputs("#IncomingInformationsTemplate");
alert("Hidden: " + listOfTemplateInputs.Hidden.length + ", Fields: " + listOfTemplateInputs.Fields.length);
function checkInputs(target) {
var ListOfFields = [];
var ListOfCheckBoxes = [];
var ListOfHidden = [];
$(target + " input[type='text'], textarea, input[type='password']").each(function() {
var input = $(this);
ListOfFields.push(input);
});
$(target + " input[type='checkbox']").each(function() {
var input = $(this);
ListOfCheckBoxes.push(input);
});
$(target + " input[type='hidden']").each(function() {
var input = $(this);
ListOfHidden.push(input);
});
var inputList = {
Fields: ListOfFields,
CheckBoxes: ListOfCheckBoxes,
Hidden: ListOfHidden
};
return inputList;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="IncomingInformationsTemplate" style="display: none">
<tr class="">
<input autocomplete="off" name="IncomingInformations.Index" type="hidden" value="5eda7c21-9b4e-4eb5-b992-6a3ea16a46cd" />
<td>
<div>
<input type="hidden" name="country" value="Norway">
<input type="hidden" name="country2" value="Germany">
<input type="text" name="Name" value="Tom">
<input type="text" name="Name2" value="Lisa">
</div>
</td>
</tr>
</div>
you should find inputs with this method
$('#IncomingInformationsTemplate').find(':input').each(function(i,e) {
console.log((i+1)+'. '+$(e)[0].outerHTML);
$(e).addClass('manipulate-it'); //manipulate it
});

knockout.js making remove button work in two viewmodels connected in one

This is my code
<div data-bind="with: SimpleListModel">
<form data-bind="submit: addItem" >
New item:
<input data-bind='value: itemToAdd, valueUpdate: "afterkeydown"' />
<button type="submit" data-bind="enable: itemToAdd().length > 0">Add</button>
<p>Your items:</p>
<select multiple="multiple" width="50" data-bind="options: items"> </select>
</form>
</div>
<div data-bind="with: SimpleListModel2">
<ul data-bind="foreach: cardlists">
<li>
<span data-bind="text: $data"></span>
Del
</li>
</ul>
</div>
this is the viewmodel
var SimpleListModel = function(items) {
this.items = ko.observableArray(items);
this.itemToAdd = ko.observable("");
this.addItem = function() {
if (this.itemToAdd() != "") {
this.items.push(this.itemToAdd()); // Adds the item. Writing to the "items" observableArray causes any associated UI to update.
this.itemToAdd(""); // Clears the text box, because it's bound to the "itemToAdd" observable
}
}.bind(this); // Ensure that "this" is always this view model
};
var SimpleListModel2 = function(cardlists) {
var self = this;
self.cardlists= ko.observableArray(cardlists);
self.removecard = function (cardlist) {
self.cardlists.remove(cardlist);
};
};
var masterVM = (function () {
var self = this;
self.SimpleListModel= new SimpleListModel(["Alpha", "Beta", "Gamma"]);
self.SimpleListModel2= new SimpleListModel2([ "Tall Hat", "LongCloak"]);
})();
ko.applyBindings(masterVM);
This is replica in my project. The remove button stops working when i had the second viewmodel. $root.removecard is coming undefined. how can i get my $root.removecard working in this scenario with one mainviewmodel.
It works when you change $root.removecard with $parent.removecard.
var SimpleListModel = function(items) {
this.items = ko.observableArray(items);
this.itemToAdd = ko.observable("");
this.addItem = function() {
if (this.itemToAdd() != "") {
this.items.push(this.itemToAdd()); // Adds the item. Writing to the "items" observableArray causes any associated UI to update.
this.itemToAdd(""); // Clears the text box, because it's bound to the "itemToAdd" observable
}
}.bind(this); // Ensure that "this" is always this view model
};
var SimpleListModel2 = function(cardlists) {
var self = this;
self.cardlists= ko.observableArray(cardlists);
self.removecard = function (cardlist) {
self.cardlists.remove(cardlist);
};
};
var masterVM = (function () {
var self = this;
self.SimpleListModel= new SimpleListModel(["Alpha", "Beta", "Gamma"]);
self.SimpleListModel2= new SimpleListModel2([ "Tall Hat", "LongCloak"]);
})();
ko.applyBindings(masterVM);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="with: SimpleListModel">
<form data-bind="submit: addItem" >
New item:
<input data-bind='value: itemToAdd, valueUpdate: "afterkeydown"' />
<button type="submit" data-bind="enable: itemToAdd().length > 0">Add</button>
<p>Your items:</p>
<select multiple="multiple" width="50" data-bind="options: items"> </select>
</form>
</div>
<div data-bind="with: SimpleListModel2">
<ul data-bind="foreach: cardlists">
<li>
<span data-bind="text: $data"></span>
Del
</li>
</ul>
</div>

How to change ng-init value with function?

Here is my Html and JavaScript code and I want to change it through function.
Html:
<div class="container" ng-app="myApp" ng-controller="myController">
<h2>{{title}}</h2>
<ul ng-init="initItems()">
<li ng-repeat="item in items">
<input ng-model="item.name" type="text"/>
<div ng-if="makeVisible == item.id && makeVisible !='' ">
<input ng-model="newname" type="text"/>
<button ng-click="hideme(item.id); rename()" type="button">
<span class="glyphicon glyphicon-ok">
</span>
</button>
<button ng-click="hideme(item.id)" type="button">
<span class="glyphicon glyphicon-remove">
</span>
</button>
</div>
<input ng-click=" showme( item.id)" type="button" value="Rename"/>
</li>
</ul>
</div>
JavaScript:
function item(id, name) {
this.id = id;
this.name = name;
};
angular.module('myApp', []).controller('myController', function($scope) {
$scope.items = [];
$scope.makeVisible = "";
$scope.initItems = function() {
$scope.items.push(new item("0", 'Vikash'));
$scope.items.push(new item("1", 'Kumar'));
$scope.items.push(new item("2", 'Vishal'));
$scope.items.push(new item("3", 'Ajay'));
};
$scope.renameThis = function(index, oldValue) {
console.log("oldValue==" + oldValue);
console.log("indexx==" + index);
var id = 'box-' + index;
console.log("Id : " + id);
document.getElementById(id).style.display = "block";
console.log('jai hind');
};
$scope.showme = function(id) {
$scope.makeVisible = id;
console.log('id', id);
};
$scope.hideme = function(id) {
console.log(item);
$scope.makeVisible = "";
};
$scope.title = 'Enter new name here';
$scope.rename = function() {
$scope.item.name = $scope.newname;
console.log('dfasdd');
};
});
Here is value in ng-init which is showing in input box 1 and I want to change it with value of second input box on click. how can I do this?
I also add a function on button.
add visible attr in item,
function item(id, name) {
this.id = id;
this.visible=false;
this.name = name;
}
and change show and hide function to this code
$scope.hideme = function(item) {
item.visible=false;
};
$scope.showme = function(item) {
item.visible=true;
};
and change this code
<div ng-if="makeVisible == item.id && makeVisible !='' ">
to:
<div ng-if="item.visible">
and send item object to shomme and hideme function
<input ng-click="showme(item)" type="button" value="Rename"/>
<button ng-click="hideme(item); rename()" type="button">
<span class="glyphicon glyphicon-ok">
</span>
</button>
<button ng-click="hideme(item)" type="button">
<span class="glyphicon glyphicon-remove">
</span>
</button>
As I understand, you want to change value of first input box (item.name) with value of second input box (newname) by function rename triggered on-click (lets say Rename button).
Solution for that is to pass item and newname to function.
Simplified HTML:
<ul ng-init="initItems()">
<li ng-repeat="item in items">
<input ng-model="item.name" type="text" />
<input ng-model="newname" type="text" />
<input ng-click="rename(item, newname)" type="button" value="Rename" />
</li>
</ul>
Controller:
$scope.rename = function(item, newname_) {
item.name = newname_;
};
See working http://jsfiddle.net/vp2r52pb/
As you are using ng-if the newname model will be available only when an item is in rename mode.
So, you can do like this:
function item(id, name) {
this.id = id;
this.name = name;
};
angular
.module('myApp', [])
.controller('myController', function($scope) {
$scope.items = [];
$scope.makeVisible = '';
$scope.title = 'Enter new name here';
$scope.initItems = function() {
$scope.items.push(new item('0', 'Vikash'));
$scope.items.push(new item('1', 'Kumar'));
$scope.items.push(new item('2', 'Vishal'));
$scope.items.push(new item('3', 'Ajay'));
};
$scope.showme = function(id) {
$scope.makeVisible = id;
};
$scope.hideme = function(id) {
$scope.makeVisible = '';
};
$scope.rename = function(item, newname) {
item.name = newname;
};
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="container" ng-app="myApp" ng-controller="myController">
<h2>{{title}}</h2>
<ul ng-init="initItems()">
<li ng-repeat="item in items">
<input ng-model="item.name" ng-disabled="true" type="text"/>
<div ng-if="makeVisible === item.id && makeVisible !== ''">
<input ng-model="newname" type="text" />
<button ng-click="hideme(item.id); rename(item, newname);" type="button">
<span class="glyphicon glyphicon-ok"></span>
</button>
<button ng-click="hideme(item.id)" type="button">
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
<input ng-if="makeVisible !== item.id" ng-click="showme(item.id)" type="button" value="Rename"/>
</li>
</ul>
</div>

Nested foreach binding not displaying correctly

I'm trying to display an observableArray within an observableArray.
It's a simple ToDo list where the tasks are assigned to certain people and I want to display each persons tasks in there own div.
I'm using knockoutjs 3.3.0
Why aren't the Tasks showing up under the person?
Here's my HTML:
<div>
<form data-bind="submit: addPerson">
<p>New Person: <input data-bind='value: personToAdd, valueUpdate: "afterkeydown"' />
<button type="submit" data-bind="enable: personToAdd().length > 0">Add</button>
</p>
</form>
<form data-bind="submit: addTask">
<p>New Task: <input data-bind='value: taskToAdd, valueUpdate: "afterkeydown"' />
<select data-bind="options: people, optionsText: 'name', value:selectedPerson"></select>
<button type="submit" data-bind="enable: taskToAdd().length > 0">Add</button>
</p>
<fieldset>
<legend>Tasks</legend>
<div data-bind="foreach: people">
<div style="float: left; padding-right: 20px;">
<label data-bind="text: name" />
<div data-bind="foreach: tasks">
<input type="checkbox" data-bind="checked: done" />
<label data-bind="text: description, style: { textDecoration: done() ? 'line-through' : 'none' }" />
</div>
</div>
</div>
</fieldset>
</form>
</div>
Here's my javascript:
var ToDoList = function (people) {
var self = this;
self.taskToAdd = ko.observable("");
self.personToAdd = ko.observable("");
self.selectedPerson = ko.observable("");
self.people = ko.observableArray(people);
self.addTask = function () {
if (self.taskToAdd() != "") {
var person = ko.utils.arrayFirst(self.people(), function (item) {
return item.name() === self.selectedPerson().name();
});
person.addTask(new Task(self.taskToAdd(), person.name()));
self.taskToAdd("");
}
};
self.addPerson = function () {
if (self.personToAdd() != "") {
self.people.push(new Person(self.personToAdd()));
self.personToAdd("");
}
}.bind(self);
};
var Task = function (task, assignee) {
var self = this;
self.task = ko.observable(task);
self.assignee = ko.observable(assignee)
self.done = ko.observable(false);
self.description = ko.pureComputed(function () {
return self.task() + " (Assigned to: " + self.assignee() + ")";
}, self);
};
var Person = function (name, tasks) {
var self = this;
self.name = ko.observable(name);
self.tasks = ko.observableArray(tasks);
self.addTask = function (task) {
self.tasks.push(task);
}.bind(self);
};
ko.applyBindings(new ToDoList());
The reason the tasks are not appearing is because your <label> tags are not closed correctly. Instead of <label data-bind="blah"/>, use <label data-bind="blah"></label>.
The tasks container is not currently rendering at all, and therefore not parsed by knockout.
To be more clear, the label with data-bind="text: name" is not closed properly AND has a text binding. The text binding is replacing the entire tasks container with the name of the person. There are two instances of this error in your sample.

Highlight when add with KnockoutJS

The goal
Highlight item when I add it to another list using KnockoutJS.
The problem
I do not how to do, and yes — I have already searched on Google and Stack, but no success; no with "add".
My HTML markup:
<div class="tooltip-quantity">
<p class="float-left">Quantity:</p>
<form data-bind="submit: Summary.addToSummary">
<input class="quantity float-left" name="productQuantity"
maxlength="2"
type="text"
data-bind="value: ProductLayout.itemQuantity,
valueUpdate: 'afterkeydown'" />
<span class="float-left">/#(Model["MeasureName"])(s)</span>
<button class="btn btn-add btn-mini float-right"
data-bind="enable: ProductLayout.itemQuantityValid">
Add
</button>
<input type="hidden" name="productId" value="#Model["ProductId"]" />
<input type="hidden" name="productName" value="#Model["ProductName"]" />
<input type="hidden" name="productMeasure" value="#Model["MeasureName"]" />
</form>
</div>
My SummaryViewModel, on JS:
function SummaryViewModel() {
var self = this;
self.products = ko.observableArray();
self.addToSummary = function (formElement) {
var $productId = $(formElement).children("[name=productId]").val();
var match = $(".summary")
.find("li[data-product-id=" + $productId + "]").length;
if (!match) {
var $productName = $(formElement)
.children("[name=productName]").val(),
$productMeasure = $(formElement)
.children("[name=productMeasure]").val(),
$productQuantity = $(formElement)
.children("[name=productQuantity]").val();
self.products.push
(new Product
($productId, $productName, $productMeasure, $productQuantity));
$.ajax({
type: "POST",
url: "/ProductsSummary/Add",
data: { productId: $productId, productQuantity: $productQuantity }
});
}
}
};
Observation: addToSummary function performs what happens when I add something to a list.
Here is a working example, for which every time your add an item to a list, it is animated : here is a jsfiddle
html:
<script type="text/html" id="tmpl">
<div>
<span data-bind="text: $data"> </span>
<span> other stuff not bound </span>
</div>
</script>
<div data-bind="template: {name: 'tmpl',foreach: Data, afterRender: $root.Animate}">
</div>
<span data-bind="text: Data().length"></span>
<button data-bind="click: AddAnItemAndAnimate">AddAnItemAndAnimate</button>
Javascript :
function ViewModel() {
var self= this;
self.Data = ko.observableArray([]);
self.AddAnItemAndAnimate = function () {
//just after the push, when the elements will be visible, the function
//Animate will be call (it is linked to the afterRender of the tempalte)
self.Data.push('added');
};
self.Animate = function(elements, index, data){
// elements contains the html representing the new item
$(elements).filter('div').fadeOut().fadeIn();
};
}
var vm = new ViewModel();
ko.applyBindings(vm);

Categories

Resources