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?
Related
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.
Having a problem selecting an id within a dynamically placed div tag on a page.
It's a date field and I'd like to have a datepicker show up when the user focuses on the field. That I'm trying to set up a plugin instead of doing any other kind of jQuery event is, I think, my problem.
So here's the dynamically loaded content that is placed on the page when a user clicks one of several radio buttons in a "calendar".
$("#s10").click(function(){
$("#S_Date").html('<input type="text" name="Start_Date" id="Start_Date" value="2016-05-24" />2016-05-24');
#S_Date is the parent div id that is loaded when the document loads.
I'm using the "PickMeUp" datepicker plugin.
From what I can tell, I need to use the on() event handler but I just can't seem to get it to bind to #Start_Date.
Here's my latest attempt at trying to call it:
var pickitup = $("#Start_Date").pickmeup({format : 'Y-m-d'});
$("#S_Date").on('focus', "#Start_Date", function(){pickitup});
With pickitup defined, I have also tried:
$("#S_Date").on('focus', "#Start_Date", pickitup);
$("#S_Date").on('focus', "#Start_Date", function(){pickmeup({format : 'Y-m-d'})}); fails out of the gate with a pickmeup is not defined error.
Ideas anyone?
So, if I'm understanding what you're doing, you want to insert some html into a given element on that click event, then apply the date picker functionality to it?
$("#s10").on("click", function() { //when the element is clicked...
//create an input with the appropriate attributes
var picker = $("<input />", { type: "text", name: "Start_Date", value: "2016-05-24" });
//append it to the desired element(s)
$("#S_Date").append(picker);
//run the plugin on it
picker.pickmeup({format: 'Y-m-d'});
});
Here's a working (simple) fiddle https://jsfiddle.net/s6vu0rnq/
The undefined error you got was because "pickmeup" is a property of jquery's prototype, but you were trying to call it from the global scope.
Also, ".click" is just an alias for ".on", so you can use either.
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 attempting to rebind the listview data after changing the template, based on a DropDownList value. I've included a JSFiddle for reference. When I rebind currently the values in the template are undefined.
Thanks!
JSFiddle link
I was thinking the best way to handle it would be in the 'select' or 'change' function:
var cboDetailsCategory = $("#detail").kendoDropDownList({
data: [
"All",
"Customer",
"Location",
"Meter",
"Other"],
select: function (e) {
var template = $("#" + e.item.text()).html();
console.log("template", template);
$("#details").html(template);
},
change: function (e) {
},
please refer to the JSFiddle link and this graphic as a visual
Here is a lengthier workflow:
User completes a name search and clicks a search button.
Name results are populated in a listview, rendered individually as button controls using a template.
User then clicks one of the name results (shown as the button text).
A dropdownlist of categories ('All' <--default , 'Location', 'Customer'...) gives the user the ability to target what subject of data they want to see. 'All' is the default, showing all details about the selected name.
So by default the 'All' template is populated.
If user wants to see the 'Location' details (template) they select it from the dropdownlist.
The template shows but the values are all blank. The only way to populate it is to click the name (button) again.
I want to remove the need for having to re-click the button (name) to populate the template ('Location', etc...).
I have put together a JSFiddle showing the structure. Though due to the data being private and served over secure network I cannot access it.
Refer to JSFiddle:
I believe the issue is that the onclick event grabs the data-uid and passes it to the initial default template (named 'All' but it's not included in code as it's lengthy). When the user changes the dropdownlist (cboDetailsCategory) and selects a new template I lose the data.
Thanks for your help. I'm really stuck on this and it's a current show stopper.
There isn't an officially supported way to change templates, without destroying the listview and rebuilding it. However, if you don't mind poking into into some private api stuff (be warned I can't guarantee that kendo won't break it without telling you) you can do this
var listview = $("#MyListview").getKendoListView();
listview.options.template = templateString;
listview.template = kendo.template(listview.options.template);
//you can change the listview.altTemplate the same way
listview.refresh(); //redraws the elements
if you want to protect against unknown API changes you can do this, which has A LOT more overhead, but no risk of uninformed change (untested!)
var listview = $("#MyListview").getKendoListView(),
options = listview.options;
options.dataSource = listview.dataSource;
listview.destroy();
$("#MyListview").kendoListView(options);
Here's the solution, thanks for everyone's help!
JSFiddle Link
The issue was where I was setting the bind:
$("#list").on("click", ".k-button", function (e) {
var uid = $(e.target).data("uid");
var item = dataSource.getByUid(uid);
var details = dropdown.value();
var template = $("#" + details).html();
$("#details").html(template);
kendo.bind($("#details"), item);
currentData = item;
});
I finally got bindings for the options and value to work on my dropdown component. What I have now works except that all javascript after the applyBinding for the value is not executed. This is not a problem when I only have one dropdown on the page at a time.
However, most of the time, I need to use more than one. When I step through the script on such a page, it executes the applyBinding for the first dropdown and stops. No further script runs, and only the first dropdown works.
Why is this? More importantly, how do I fix it?
Here are the relevant lines of code:
$(function () {
var $thisdd = $("##ddname"); //the JQuery selector for my dropdown
var dropdownItems = getDropdownItemsFromDl("#ddname");
var newitem = ko.observable({ cname: ddcname, cvalue: ko.observable($thisdd.val()), cpublishtopic: "" });
classificationsViewModel.push(newitem());
var viewModel =
{
dditems : dropdownItems
};
$("##ddname").attr("data-bind", "value: classificationsViewModel()[" + classificationsViewModel.indexOf(newitem()) + "].cvalue, options: dditems, optionsText: 'value', optionsValue: 'key'");
ko.applyBindings(viewModel);
ko.applyBindings(classificationsViewModel()[classificationsViewModel.indexOf((newitem())].cvalue);
});
When you call ko.applyBindings, Knockout will apply the model to the entire document.
This is great if you have one model for the entire page.
It seems you want one model per dropdown. See the optional parameter on http://knockoutjs.com/documentation/observables.html#activating_knockout
You can then bind to each dropdown a separate model via something like ko.applyBindings(viewModel, $('##ddname')[0]);
I don't understand what this blurb is trying to do:
value: classificationsViewModel()[" + classificationsViewModel.indexOf(newitem()) + "].cvalue
It seems you're trying to use two different models to control the dropdown. I am fairly certain that won't end well. Try using one model to rule them all to handle all the dropdowns. I think you'll find it much easier to maintain and logic about.