Knockout: accessing viewmodel instance in HTML template - javascript

I am having a viewmodel and an associated template as below.
var AilmentItem = function () {
this.SelectedAilment = ko.observable();
}
function AilmentsViewModel() {
this.Ailments = ko.observableArray([new AilmentItem()]);
this.AilmentsType = ko.observableArray([{ Name: 'Diabetes' }, { Name: 'Arthritis' }, { Name: 'High BP'}]);
}
HTML script
<script type="text/javascript">
$(function () {
var AilmentsVM = new AilmentsViewModel();
ko.applyBindings(AilmentsVM, $('#Ailments')[0]);
});
</script>
<div id="Ailments">
<div>
<table>
<tbody data-bind='template: { name: "ailmentRowTemplate", foreach: Ailments }'>
</tbody>
</table>
</div>
</div>
<script type="text/html" id="ailmentRowTemplate">
<tr>
<td><select data-bind="options: AilmentsVM.AilmentsType(), optionsText: 'Name', value: SelectedAilment"></select></td>
</tr>
</script>
In the HTML template I need to bind AilmentsType to one of the columns as drop down. Can someone guide me how to achieve it? Thanks.

Your AilmentsVM does not have global scope, because it is being created in your jQuery ready block, so you can't access it directly in a data-bind.
If you are using 1.3 beta, then you can use either the $root or $parent special variables that Knockout provides. In this case, they would be the same, as you are only one level in from the top-level scope. So, just do: $root.AilmentsType.
If you are using an earlier version, then you can use the templateOptions functionality to pass options to a jQuery template. It would look like this:
<tbody data-bind='template: { name: "ailmentRowTemplate", foreach: Ailments, templateOptions: { types: AilmentsType } }'>
</tbody>
Then, access it like:
<select data-bind="options: $item.types, optionsText: 'Name', value: SelectedAilment"></select>

Related

Set and modify a value in a select box with knockout

Well, I have two problems that worry me a lot ... First, I don't know how to give a default value to the select box.
And I I'm not able to change the value of the select box via an event click ... I've created a fiddle example if someone could give me a hand it would be very appreciated!
HTML
<select id="FilterBox" data-bind="value: siteGetOne">
<option value="-2">City Wide</option>
<!-- ko foreach: sites -->
<option data-bind="text: name, value: $data"></option>
<!-- /ko -->
</select>
Selection Option Object : <span data-bind="text: siteGetOne"></span><br/>
Selection Option name : <span data-bind="text: siteGetOne().name"></span><br/>
Selection Option id : <span data-bind="text: siteGetOne().id"></span><br/>
Set Value to 1
Set Value to 2
Set Value to 3
JS
var viewModel = function() {
var self = this;
setValue = ko.observable();
self.sites = [
{ name: 'Site 1', id: 1},
{ name: 'Site 2', id: 2},
{ name: 'Site 3', id: 3}
];
self.siteGetOne = ko.observable(self.sites[2].id);
self.siteGetOne.subscribe(function (newValue) {
console.log(newValue);
}, self);
}
ko.applyBindings(new viewModel());
http://jsfiddle.net/xjYcu/276/
Edited Final version : http://jsfiddle.net/xjYcu/286/
couple things you may want to change.
here is the entire fiddle. http://jsfiddle.net/xjYcu/283/
the first one is you should use the options binding for your select.
<select id="FilterBox" data-bind=" options: sites,
optionsText: 'name',
value: siteGetOne,
optionsCaption: 'Choose...'">
</select>
also try changing your click bindings to something like this so you can pass in your parameter.
Set Value to 1
Set Value to 2
Set Value to 3

Knockout switches template between forEach and data

I want a dynamic container to show all of my content, so I have a model like this:
function ContentViewmodel() {
var engines = ko.observableArray(),
application = ko.observable({ name: 'luna-content-engines', foreach: engines });
function registerEngine(engine) {
engines.push(engine);
}
function showConsoleContent() {
application({ name: 'luna-console-template' });
}
function showEngineContent() {
application({ name: 'luna-content-engines', foreach: engines });
}
return {
registerEngine: registerEngine,
engines: engines,
showConsoleContent: showConsoleContent,
showEngineContent: showEngineContent,
application: application
};
<div id="luna-content-container" data-bind="template: content"></div>
<script type="text/html" id="luna-content">
<div class="luna-content-menu">
<div class="luna-content-menu-item" data-bind="click: showEngineContent">Engines</div>
<div class="luna-content-menu-item" data-bind="click: showConsoleContent">Console</div>
</div>
<div>
<div class="luna-content-engines-container" data-bind="template: application"></div>
</div>
</script>
If I switch from default to content it works perfectly, but switching back to engines, with forEach doesn't work; if I change it back to normal data, it works again.
Maybe I do something wrong with the object binding. Any suggestion, even with a complete different approach?

Trying to get specific elements from an observable array

I am trying to get specific values from an observablearray. In this example I'm trying to get the number of two values I have created in a array.
I have set the code up like this:
HTML
<div id="test" style="width: 100%">
<table style=" width: 50%; display: block; float: left; margin: 0; padding: 0; border: none">
<tr>
<td>Item 1</td>
<td><span data-bind="text: someArray()[0].number"></span></td>
</tr>
<tr>
<td>Item 2</td>
<td><span data-bind="text: someArray()[1].number"></span></td>
</tr>
</table>
</div>
JavaScript
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.0.3.min.js" type="text/javascript"></script>
<script src="https://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js" type="text/javascript"></script>
<script type="text/javascript">
var viewModel = {
someArray: ko.observableArray([]) //
}
ko.applyBindings(viewModel);
$(function () {
getData();
});
var getData = function () {
viewModel.someArray([
{
number: 123,
text: "abc"
},
{
number: 456,
text: "def",
}
]);
}
</script>
I have also uploaded it to JSfiddle.
How can I access specific positions in the array?
The following works:
var viewModel = {
someArray: ko.observableArray([]) //
}
var getData = function () {
viewModel.someArray.push(
{number: 123,text: "abc"},
{number: 456,text: "def"},
{number: 789,text: "ghi"}
);
}
getData();
ko.applyBindings(viewModel);
You were pushing an array into viewModel.someArray rather than 3 separate objects. You also have to apply the bindings after inserting the array objects or else you will get a cannot parse binding exception when there are no rows in someArray.
You might consider using the foreach binding to better fit your needs Knockout Foreach Binding. Then you can call applyBindings anytime. If you're going to have other rows in the array that you don't want, create a computed observable array out of the indices that you do want and build a foreach binding around that.
Your fiddle doesn't work for a few reasons, the biggest being that you're trying to use JQuery, but it's not loaded into the page.
Here's the modified javascript that works:
var viewModel = {
someArray: ko.observableArray([]) //
}
var getData = function () {
viewModel.someArray.push(
{
number: 123,
text: "abc"
});
viewModel.someArray.push(
{
number: 456,
text: "def",
});
viewModel.someArray.push(
{
number: 789,
text: "ghi",
});
}
getData();
ko.applyBindings(viewModel);

Bootstrap-select with Knockout.js custom binding

I am making Add or Invite option on my site , I need to fetch first all the users of the site and show them either in typeahead or something like select picker option and as soon as the user is selected the user should be added to the invite list. That is something like trello invite to the board or organisation.
See here trello: https://trello.com/
At the very basic step I am trying to use knockout live tutorial example list and collections example. (http://learn.knockoutjs.com/#/?tutorial=collections)
and Here is my code
HTML
<h2>Your seat reservations (<span data-bind="text: seats().length"></span>)</h2>
<button class="btn btn-deffault" data-bind="click: addSeat, enable: seats().length < 5">Reserve another seat</button>
<table>
<thead><tr>
<th>Passenger name</th><th>Meal</th><th>Surcharge</th><th></th>
</tr></thead>
<!-- Todo: Generate table body -->
<tbody data-bind="foreach: seats">
<tr>
<td><input data-bind="value: name" /></td>
<td><select class="selectpicker" data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'" data-live-search="true"></select></td>
<td><input data-bind="value: formattedPrice"></td>
<td>Remove</td>
</tr>
</tbody>
</table>
<h3 data-bind="visible: totalSurcharge() > 0">
Total surcharge: $<span data-bind="text: totalSurcharge().toFixed(2)"></span>
</h3>
and here is knockout code
//custom binding for selectpicker
ko.bindingHandlers.selectPicker = {
init: function (element, valueAccessor, allBindingsAccessor) {
if ($(element).is('select')) {
if (ko.isObservable(valueAccessor())) {
ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor);
}
$(element).selectpicker();
}
},
update: function (element, valueAccessor, allBindingsAccessor) {
if ($(element).is('select')) {
var selectPickerOptions = allBindingsAccessor().selectPickerOptions;
if (typeof selectPickerOptions !== 'undefined' && selectPickerOptions !== null) {
var options = selectPickerOptions.options,
optionsText = selectPickerOptions.optionsText,
optionsValue = selectPickerOptions.optionsValue,
optionsCaption = selectPickerOptions.optionsCaption;
if (ko.utils.unwrapObservable(options).length > 0) {
ko.bindingHandlers.options.update(element, options, ko.observable({ optionsText: optionsText, optionsValue: optionsValue, optionsCaption: optionsCaption }));
}
}
if (ko.isObservable(valueAccessor())) {
ko.bindingHandlers.value.update(element, valueAccessor);
}
$(element).selectpicker('refresh');
}
}
};
function AllUsers(data){
var self = this;
self.name = name;
self.meal = ko.observable(initialMeal);
self.formattedPrice = ko.computed(function() {
var price = self.meal().price;
return price ? "$" + price.toFixed(2) : "None";
});
self.formatPrice = ko.observable(self.formattedPrice());
self.about_me = ko.observable(data.about_me);
self.email = ko.observable(data.email);
self.uname = ko.observable(data.uname);
self.uuid = ko.observable(data.uuid);
self.everyuser = [
{aboutMe: self.about_me(), email: self.email(), name: self.uname, id: self.uuid()}
];
}
function PostViewModel() {
var self = this;
self.allusers= ko.observableArray([]);
self.gert = [
{ mealName: "Standard (sandwich)", price: 0 },
{ mealName: "Premium (lobster)", price: 34.95 },
{ mealName: "Ultimate (whole zebra)", price: 290 }
];
$.getJSON('/users', function (json) {
var t = $.map(json.users, function(item) {
console.log("Something",item);
return new AllUsers(item);
});
self.allusers(t);
});
}
ko.applyBindings(new PostViewModel());
But the code is not working and not showing the options while using class selectpicker in HTML code, and if selectpicker is not used then the simple dropdown comes that should not come.
<td><select class="selectpicker" data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'" data-live-search="true"></select></td>
anyone knowing about Knockout.js please help
It appears that you are using the name of the custom binding as your CSS class for the <select>. In order to apply the binding to the correctly you'll need to do this within the data-bind attribute.
<select data-bind="selectpicker: meal"></select>
Knockout's documentation on this is also very helpful.

Setting dropdown value attributes with knockout.js

I have used an example from the knockout tutorial stripped down to the essentials to reproduce my problem. What I cannot figure out is how to set the value attribute of the tags in the items. I added a value to each entry of self.availableMeals but however I try to add it to the it just fails to populate the dropdowns at all. When I try to add optionsValue to the binding it populates the dropdowns but doesn't select the appropriate value.
Please help!
<h2>Your seat reservations</h2>
<table>
<thead><tr>
<th>Passenger name</th><th>Meal</th><th>Surcharge</th><th></th>
</tr></thead>
<!-- Todo: Generate table body -->
<tbody data-bind="foreach: seats">
<tr>
<td><input data-bind="value: name" /></td>
<td><select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select></td>
</tr>
</tbody>
</table>
// Class to represent a row in the seat reservations grid
function SeatReservation(name, initialMeal) {
var self = this;
self.name = name;
self.meal = ko.observable(initialMeal);
}
// Overall viewmodel for this screen, along with initial state
function ReservationsViewModel() {
var self = this;
// Non-editable catalog data - would come from the server
self.availableMeals = [
{ mealName: "Standard (sandwich)", price: 0 },
{ mealName: "Premium (lobster)", price: 34.95 },
{ mealName: "Ultimate (whole zebra)", price: 290 }
];
// Editable data
self.seats = ko.observableArray([
new SeatReservation("Steve", self.availableMeals[0]),
new SeatReservation("Bert", self.availableMeals[1])
]);
}
ko.applyBindings(new ReservationsViewModel());
I figured this out. I don't know why I couldn't add a value attribute to the rendered HTML but I didn't need to. All I need to do is retrieve the selected item from the model then examine that.
<h2>Your seat reservations</h2>
<table>
<thead><tr>
<th>Passenger name</th><th>Meal</th><th></th>
</tr></thead>
<tbody data-bind="foreach: seats">
<tr>
<td><input data-bind="value: name" /></td>
<!-- this line works but doesn't try to populate value attribute OF <OPTION> -->
<td><select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName'"></select></td>
<!-- this line tries to populate value attribute with those commented out in the javascript but doesn't work -->
<!--<td><select data-bind="options: $root.availableMeals, value: meal, optionsText: 'mealName', optionsValue: 'val'"></select></td>-->
</tr>
</tbody>
</table>
<button data-bind="click: showVal">Show Value</button>
// Class to represent a row in the seat reservations grid
function SeatReservation(name, initialMeal) {
var self = this;
self.name = name;
self.meal = ko.observable(initialMeal);
}
// Overall viewmodel for this screen, along with initial state
function ReservationsViewModel() {
var self = this;
// Non-editable catalog data - would come from the server
self.availableMeals = [
{ val: 0, mealName: "Standard (sandwich)" },
{ val: 1, mealName: "Premium (lobster)" },
{ val: 2, mealName: "Ultimate (whole zebra)" }
];
// Editable data
self.seats = ko.observableArray([
new SeatReservation("Steve", self.availableMeals[0]),
new SeatReservation("Bert", self.availableMeals[1])
]);
self.showVal = function() {
alert(self.seats()[1].meal().val);
}
}
ko.applyBindings(new ReservationsViewModel());
so I can get (for example) one of the val values with self.seats()[1].meal().val
I hope this helps someone else with the same misunderstanding.
http://jsfiddle.net/bwbF3/5/

Categories