I am using Knockout-Kendo.js to bind Kendo widgets to Knockout observables. I have a KendoListView that populates itself from html template based on a observable named "Filters". The problem I am having is that the input control that I am using inside the template is not converting into a Kendo widget, even though I am specifying it as a kendoComboBox. (I have left out properties of dataSource, etc for simplicity)
Other things to take note of.
On page load, there are no objects in the Filters observable property
in the Model.
ko.ApplyBindings(Model) is called within the Document ready function.
Users make various selections on the page, which then populates the
Filter observable in the model.
The controls do show up in DOM when Filters are added, but as native Html controls.
var Model = {
Filters: ko.observable([]),
FilterItemTemplate: function () {
return kendo.template($("#FilterItemTemplate").html())
}
}
<div id="Filters" data-bind="kendoListView: { data: Filters, template: FilterItemTemplate()}" ></div>
<script type="text/html" id="FilterItemTemplate">
<div>
<h4>#=ControlLabel#</h4>
<input id="#=ControlID#" name="FilterControl" data-bind="kendoComboBox: {}" />
</div>
</script>
What I wind up doing is
Removed the ListView from the Filters div.
Since the ListView is now removed, i subscribed to the Filters observable in my model with my javascript code. So whenever something is loaded or removed from the Filters observable, the function listener will be invoked.
Within the listener function manually created the Kendo widgets and append to the Filters div.
Related
I'm using a Kendo UI Listbox control to display items. I'm populating the control by specifying a javascript array as the data source.
Here is the page markup.
<div>
<select id="selectedview"></select>
</div>
<script>
$(document).ready(function () {
$("#selectedview").kendoListBox();
});
</script>
And here is the javascript / JQuery that I am using to populate the Kendo UI Listbox control.
var listBox = $("#selectedview").data("kendoListBox");
listBox.clearSelection();
$("#selectedview").kendoListBox({
dataSource: subscribers
});
Here's the DataSource array that I am using.
When the control is displayed however the same two items are displayed multiple times in error.
What's going on and how do I fix this?
You seem to be re-creating the widget over an already existent instance, that is why it is duplicating the items. Check this out.
If you want to update the list of an already created widget instance, try either:
Change the DataSource's data:
$("#selectedview").data("kendoListBox").dataSource.data(subscribers);
To set setDataSource again:
$("#selectedview").data("kendoListBox").setDataSource(new kendo.data.DataSource({
data: subscribers
});
I am trying to initialize a dropdown widget using Foundation. The actual html for the dropdown is compiled dynamically, and multiple dropdowns exist on the page. I am having trouble initializing the dropdowns because of their dynamic nature.
Essentially my question is, how do you initialize a Foundation dropdown without an ID or data-dropdown attribute?
I have a screen with a list of data "People" on the left, and a the details of a single person on the right. The whole screen is using Knockout to bind the data to the view model.
My main View model:
self.people = ko.observableArray([]);
self.selectedPerson = ko.observable()
In my html:
<div data-bind='with: selectedPerson'>
...
<div class='my-dropdown-widget' data-bind="myCustomBinding: {data: myData}">
...
</div>
</div>
Each selectedPerson is a Person object, which has an onReady function that fires when the data from the person is rendered in the main view model. In that function, I have the following code:
self.onReady = function (el) {
var filterEl = $('.filter-widget', el).attr({
'id': self.filterWidget.ui_ID,
'data-dropdown': ''
});
setTimeout(function () {
$(el).foundation();
}, 500);
self.ui_container = $(el);
};
I have to have the dropdown widget on the page (as opposed to loading the HTML for it) so i can apply bindings to it. Applying Bindings on dynamically loaded html messes up the widget's binding context.
This approach fails with the following message:
Uncaught TypeError: Cannot read property 'className' of undefined
This error usually occurs because the element does not have a data-dropdown attribute, which I am adding dynamically.
If I do this the way that is illustrated in the Foundation Docs, and add an ID and data-dropdown attribute to the dropdown element, the dropdown works, but only for the first selectedPerson. In other words, if I navigate to more than one person, the dropdown stops working properly.
How can I get these dropdowns to work given the setup of my page?
I'm working with a form and would like to add ng-model on dynamic input elements. I have a scope variable defined as:
$scope.formData = {};
On the page there are a couple of drop-down lists that users can choose an option from and based on those options we are appending some input fields to form body.
formBody.append('<input ng-model="formData.'+obj.Title+'" type="number"></input></br>');
This is not working for me because I'm assuming once the controller runs it can't register any new ng-model. Is there way to add dynamic ng-model or there is a different approach to what I'm trying to do (i.e. build predefined views that can be loaded on the page)?
EDIT:
I have created a jsfiddle that outlines what I'm trying to do - http://jsfiddle.net/k5u64yk1/
If you need to dynamically add html with dynamic bindings that cannot be encapsulated into ng-repeat, ng-if, etc, you have to call $compile on the template once it has been modified to alert AngularJS that it has to reparse the template and initiate a new digest cycle. This will pick up any new ng-model bindings and appropriately tie them to your scope.
HTML:
<div ng-app="MyApp" ng-controller="MyCntrl">
<button ng-click="addInput()">Add Input</button>
<div id="form">
input would go here.
</div>
</div>
JS:
By placing your add input inside of a click event, you avoid an infinite compile loop. Note that this currently resets the state of your form, so if you wanted to work around that you'd need to capture your form state and restore it after compile.
$scope.addInput = function () {
var aForm = (angular.element(document.getElementById('form')));
if ($scope.data["Digital Conversation"][0].MetricType.Title === "Number") {
aForm.append(
'<input ng-model="formData.' +
$scope.data["Digital Conversation"][0].Title.Title +
'" type="number"></input>');
}
$compile(aForm)($scope);
}
You can find the working jsfiddle here: http://jsfiddle.net/k5u64yk1/
I have an AJAX MVC Contrib Grid implementation, that already existed and now I am in a situation where I am trying to bolt on some knockout functionality... and I want to know if this is possible without changing the whole grid implementation.
This is the refresh grid function that is setting the container html when the pagination changes.
scope.refreshGrid = function (container, url) {
if (url)
container.data(scope.selectors.actionUrlAttribute, url);
$.post((url || container.data(scope.selectors.actionUrlAttribute)), scope.getParams(),
function(html) {
container.html($(html).html());
scope.bindDeleteButtons();
}).done(function() {
container.trigger("refresh.ctb.grid");
});
}
one of the columns for the grid is custom column that uses Html.Partial like this:
column.Custom(x => Html.Partial("_CartSelection", new CartSelection(x.Id)));
The partial view has the below markup with some knockout data bindings
<input type="checkbox" value="#Model.Id" data-bind="enable: (selectionEnabled() || $element.checked), checked: selectionIds" />
This works for the first page of results, when the paging is selected to change the page and the container html() is updated the bindings no longer work but the KO viewModel still has the correct selectionIds.. which is what I was expecting to happen.
The KO view model is being applied as shown below, where the grid has a wrapper parent div with an id of "cart":
$(function() {
var viewModel = new IP.Configuration.CartSelector(new IP.Router());
ko.applyBindings(viewModel, document.getElementById("cart"));
});
I have already seen comments in other posts about how you shouldn't re-apply bindings. In my case it seems I want to apply bindings but only to some child nodes that are being dynamically loaded.
Is this possible?
UPDATE:
Almost had this working by adding a cart-selection class to each checkbox and doing the below in a rebind function on the viewModel, where self is the viewModel:
$("#cart .cart-selection").each(function(index, item) {
ko.applyBindings(self, item);
});
Then doing the below on the custom trigger for refreshing the grid, when the content is reloaded.
$("#cartGrid").on("refresh.ctb.grid", function() {
viewModel.rebind();
});
The issue I am finding with this at the moment is that the checkboxes are no longer enabled regardless of the $element.checked binding.. maybe a valueHasMutated will fix this, still looking into this.
I figured out what my remaining problem was, it was due to the ordering of the data bindings.
The enable data bind needed to be placed after the checked binding since it has a dependency on it via $element.checked which makes sense now after realising it!!
I changed my rebind function slightly to the below:
var gridResult = $("#cartGrid table");
if (gridResult.length > 0)
ko.applyBindings(this, gridResult[0]);
Each refresh brings in a new table but at least now if I add any more bindings to other elements in the results from the grid, they will work as expected.
I'm just looking at Knockout JS and how I could integrate it with an MVC3 project I'm building.
Looking at the examples where data is brought down from the server, the knockout view model (KVM) is always populated by an Ajax call after the page has been rendered.
Is this the normal way of doing things?
My page currently renders controls using templated editor templates, eg:
#Html.DropDownListFor(m => m.Holiday.Destination, SelectListHelpers.ToSelectList(Model.HolidayModel.Destinations, Model.Holiday.Destination), new { #class = "optionselect", data_bind = "value: Destination" })
However, if using Knockout, shouldn't I be outputting the data that makes up the select list as an array within a script block and then using the knockout binding to fill the select list?
Thanks for any advice on this.
A common and easy way to do this is to serialize your model values to the page. This would be something like:
var viewModel = {
choices: ko.observableArray(#Html.Raw(Json.Encode(Options))),
selectedChoices: ko.observableArray(#Html.Raw(Json.Encode(SelectedOptions)))
};
Then, just use a standard data-bind on your select like:
data-bind="options: choices, selectedOptions: selectedChoices"