display ko.observable with html binding - javascript

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

Related

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>

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.

How to make bootstrap time picker close?

How do I make the second time picker close after setting the time? It just stays open even if I click on the submit button on the webpage.
http://jsfiddle.net/jkittell/z485769h/1/
HTML code:
<div class="container">
<h1>Select Two Times</h1>
<form>
<br />
<input type="text" data-bind="value: startTime" name="start_time" class="timepicker" placeholder="h:mm PM" data-default-time="false"></input>
<input type="text" data-bind="value: endTime" name="start_time" class="timepicker" placeholder="h:mm PM" data-default-time="false"></input>
</form>
<button data-bind="click: submit">Click Me</button>
<br />
<p>You selected: <span data-bind="text: timeSpan"></span></p>
</div>
Knockout.js code:
$(function () {
$('.timepicker').timepicker();
function ViewModel() {
var self = this;
self.startTime = ko.observable();
self.endTime = ko.observable();
self.timeSpan = ko.computed(function () {
return self.startTime() + " - " + self.endTime();
}, this);
self.submit = function () {
alert("Time submitted");
};
}
ko.applyBindings(new ViewModel());
});
$('.bootstrap-timepicker-widget').removeClass('open');
DEMO: http://jsfiddle.net/z485769h/2/

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);

add object to observable array using knockout

For some reason i'm having trouble passing an object to observable array.
function CalendarViewModel() {
var self = this;
self.event = {
name : ko.observable(""),
adress : ko.observable(""),
startTime : ko.observable(""),
endTime : ko.observable("")
}
self.events = ko.observableArray([
])
self.addEvent = function (event) {
self.events.push(event);
alert(self.events.length)
alert(self.events[0].name());
}
my view:
<fieldset class="add-event-fieldset">
<div data-bind="with: event">
<legend>Add Event</legend>
<div style="text-align: center;">
<label class="title-label">What </label>
</div>
<div>
<label>Name: </label>
<input type="text" name="whatTxtBox" data-bind="value: name" />
</div>
<div>
<label>Where: </label>
<input type="text" name="whereTxtBox" data-bind="value: adress" />
</div>
<div style="text-align: center;">
<label class="title-label">When </label>
</div>
<div>
<label>start: </label>
<input type="text" id="startHourTxtBox" data-bind="value: startTime" />
</div>
<div>
<label>end: </label>
<input type="text" id="endHourTxtBox" data-bind="value: endTime" />
</div>
</div>
<input type="hidden" name="" id="hiddenDay" />
<button id="btnAddNewEvent" data-bind="click: $root.addEvent">+</button>
</fieldset>
The alerts show that the array is always empty, please explain what i'm doing wrong thanks.
Your observable array usage e.g self.events.push(event); is correct (because observable array implements push), only your alerts are wrong.
The correct calls would be
alert(self.events().length)
alert(self.events()[0].name());
Because you need to call the observable array as a function like the regular ko.observable to get its underlying value the array itself.
However you are currently adding to whole CalendarViewModel to the array because the btnAddNewEvent is outside of yourwith binding so the current context will be your main view model.
One way to solve it: just add the self.event to the array, so:
self.addEvent = function()
{
self.events.push(self.event);
alert(self.events().length)
alert(self.events()[0].name());
}
But this can cause problems later when you want to add another element because you will end up referencing the same element, so the right solution is copy the properties somewhere:
So I would create a constructor function for your event class:
var Event = function(data) {
var self = this;
self.name = ko.observable(data.name()),
self.adress = ko.observable(data.adress()),
self.startTime = ko.observable(data.startTime()),
self.endTime = ko.observable(data.endTime())
}
And push a new event in the addEvent
self.events.push(new Event(self.event));
Try
self.events().length
and
self.events()[0].name()
instead.
Just updating a little on nemesev answer. You really don't have to pass data as an argument
var Event = function() {
var self = this;
self.name = ko.observable();
self.adress = ko.observable();
self.startTime = ko.observable();
self.endTime = ko.observable();
};
And call it like
self.events.push(new Event());

Categories

Resources