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);
Related
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>
I'm working on a list app where initially the user is presented with an input and button. In the input the user enters the name of a new list, and after the button is clicked, an empty list appears ready for input of items. Adding a new list works, as does adding/removing list items. But the name of the list doesn't print on the page. Currently without any advanced CSS, it's expected for the lists' names to all appear at the top of the page rather than directly above their respective lists.
https://codepen.io/anon/pen/RVmeLe
HTML:
<div ng-app="notepadApp">
<div ng-controller="notepadController as notepadCtrl">
<header ng-repeat="list in notepadCtrl.lists">
<form name="removeListForm" ng-submit="notepadCtrl.removeList($index)">
<input type="submit" value="Remove list">
</form>
<h1>{{list.name}}</h1>
</header>
<div ng-repeat="list in notepadCtrl.lists" class="shoppingList" ng-controller="ItemController as itemCtrl">
<ul>
<li ng-repeat="item in list.items">
<label>
<input type="checkbox" ng-model="item.checked">
<span class="item-name-wrapper">{{item.name}}</span>
</label>
<form name="itemForm" ng-submit="itemCtrl.removeItem(list, $index)">
<input type="submit" value="remove">
</form>
</li>
</ul>
<form name="itemForm" ng-submit="itemCtrl.addItem(list)">
<input type="text" ng-model="itemCtrl.item.name">
<input type="submit" value="Add item">
</form>
</div>
<form name="addListForm" ng-submit="notepadCtrl.addList(newListName)">
<input type="text" ng-model="notepadCtrl.list.name">
<input type="submit" value="Add list">
</form>
</div>
</div>
Javascript:
(function(){
var app = angular.module('notepadApp', []);
var shoppingLists = [
];
app.controller('notepadController', function(){
var notepadCtrl = this;
notepadCtrl.lists = shoppingLists;
notepadCtrl.addList = function(newListName) {
var newList = {
name: newListName,
items:[]
};
shoppingLists.push(newList);
};
notepadCtrl.removeList = function(index) {
shoppingLists.splice(index, 1);
};
});
app.controller('ItemController', function(){
this.item = {};
this.addItem = function(list){
list.items.push(this.item);
this.item = {};
};
this.removeItem = function(list, index) {
list.items.splice(index, 1);
};
});
})();
You just want to replace:
ng-submit="notepadCtrl.addList(newListName)"
with:
ng-submit="notepadCtrl.addList(notepadCtrl.list.name)"
I have create unordered list where user can click and edit(update) item. I have some problem hiding/showing divs logic. I have showItem div and editItem div when user click on edit it show editItem div and hide showItem but the cancel button is not working right when user click it will hide editItem div but will not open it
html
<ul>
<li data-ng-repeat="value in model.rrnConditionsValues">
<div id="showItem" data-ng-show="!isVisible(value)">
<input class="" type="submit" value="Edit" data-ng-click="toggleVisibility(value)">
<input class="" type="submit" value="Delete" data-ng-click="deleteValue(value)">
<label>{{value.formControllerValueName}}</label>
</div>
<div id="editItem" data-ng-hide="!isVisible(value)">
<input class="" type="submit" value="update" data-ng-click="updateValue(value)">
<input class="" type="submit" value="Cancel" data-ng-click="toggleVisibility(value)">
<input type="text" size="30" data-ng-model="value.formControllerValueName" placeholder="add new here">
</div>
</li>
</ul>
javascript
$scope.updateValue = function (value) {
itemsManagementService.updateValue(value);
};
$scope.deleteValue = function (value) {
};
$scope.toggleVisibility = function (model) {
$scope.selected = model;
};
$scope.isVisible = function (model) {
return $scope.selected === model;
};
$scope.hide = function () {
return $scope.isVisible = false;
};
You could add a scope variable editingMode to store if the current item is in editing mode and also you should store the value before entering the edit mode so you can restore the old value after cancel click.
Please have a look at the demo below or in this jsfiddle.
angular.module('demoApp', [])
.controller('mainController', function ($scope) {
$scope.editingMode = [];
$scope.backup = [];
$scope.model = {
rrnConditionsValues: [{
formControllerValueName: "a"
}, {
formControllerValueName: "b"
}, {
formControllerValueName: "c"
}, {
formControllerValueName: "d"
}]
};
$scope.updateValue = function (value, index) {
//itemsManagementService.updateValue(value); // just removed for the demo
$scope.editingMode[index] = false;
};
$scope.cancel = function (index) {
$scope.model.rrnConditionsValues[index].formControllerValueName
= $scope.backup[index];
$scope.editingMode[index] = false;
};
$scope.toggleEdit = function (index) {
// save current model value so we can restore it on cancel
$scope.backup[index] = $scope.model.rrnConditionsValues[index].formControllerValueName;
console.log($scope.backup);
$scope.editingMode[index] = !$scope.editingMode[index];
//$scope.selected = model;
};
$scope.deleteValue = function(index) {
$scope.model.rrnConditionsValues.splice(index,1);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController">
<ul>
<li data-ng-repeat="value in model.rrnConditionsValues">
<div id="showItem" data-ng-show="!editingMode[$index]">
<input class="" type="submit" value="Edit" data-ng-click="toggleEdit($index)">
<input class="" type="submit" value="Delete" data-ng-click="deleteValue($index)">
<label>{{value.formControllerValueName}}</label>
</div>
<div id="editItem" data-ng-show="editingMode[$index]">
<input class="" type="submit" value="update" data-ng-click="updateValue(value, $index)">
<input class="" type="submit" value="Cancel" data-ng-click="cancel($index)">
<input type="text" size="30" data-ng-model="value.formControllerValueName" placeholder="add new here">
</div>
</li>
</ul>
</div>
Since is a toggle, all you had to do is check if the model you are sending is the same as already are inside the selected. if it's , just set it to null.
$scope.toggleVisibility = function (model) {
if($scope.selected === model){
$scope.selected = null;}
else{
$scope.selected = model;
}
};
Jsfiddle of example
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.
Check out this fiddle: http://jsfiddle.net/XuMzS/4/
html:
<input data-bind="value: Total" type="text" />
<textarea cols="50" rows="10" data-bind="value: testHtml, valueUpdate: 'afterkeydown'">
</textarea>
<p>Html:</p>
<div class="wrapper">
<div data-bind="html: testHtml"></div>
<br />
</div>
javascript:
function viewModel() {
var self = this;
self.Total = ko.observable("1337");
self.testHtml = ko.observable();
}
ko.applyBindings(new viewModel());
What I am trying to do is to display the observable Total by writing the code that is needed inside the textarea (which displays html in the div below it).
Like if I wrote:
<span data-bind="text: Total"></span>
But nothing is displayed if I write that code in. Otherwise normal html is working.
Is there some way you can do this?
I made a sample, I think this is what you are looking for.
function viewModel() {
var self = this;
self.Total = ko.observable("1337");
self.testHtml = ko.observable("<b>test</b><span data-bind=\"text: Total\"></span>");
self.testHtmlWrapper = ko.computed(function () {
return '<div id="dynamicContent">' + self.testHtml() + '</div>';
});
self.rebind = function () {
try {
ko.applyBindings(self, document.getElementById("dynamicContent"));
} catch (e) {
}
};
self.testHtml.subscribe(self.rebind);
}
var vm = new viewModel();
ko.applyBindings(vm);
vm.rebind();
See Fiddle
I hope it helps.
Why do you need the testHtml observable?
This can easily be accomplished using the code below.
Viewmodel:
function viewModel() {
var self = this;
self.Total = ko.observable("1337");
}
ko.applyBindings(new viewModel());
Html:
<input data-bind="value: Total" type="text" />
<textarea cols="50" rows="10" data-bind="valueUpdate: 'afterkeydown'">
<b>test</b><span data-bind="text: Total"></span>
</textarea>
<p>Html:</p>
<div class="wrapper">
<div><b>test</b><span data-bind="text: Total"></span></div>
<br />
</div>
See this fiddle