How to rebind a Kendo ListView after changing template - javascript

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

Related

Get the value of a Combobox select in WP editor

In a Wordpress installation I have a custom post type and a metabox with custom post_meta fields.
Parent dropdown field in Gutenberg's sidebar used to be a <select> element. I have some scripts that onChange trigger the hide/show of different fields making them conditional, depending whether the page being edited is a parent or child:
$(document).on("change", ".editor-page-attributes__parent select", function(){
toggleFields();
}
The options in the <select> have IDs as values so I could get Title and ID for the selected parent and dynamically show some data in the metabox for my user:
var dropdown = $('.editor-page-attributes__parent select');
var parentName = dropdown.find(':selected').text();
var parentId = dropdown.val();
Since v5.6 Wordpress has replaced that select element with a Combo Box. I have tried to get the same data onChange and only had some success using blur:
$(document).on("blur", ".editor-page-attributes__parent .components-combobox-control__input", function(){
toggleFields();
var parentName = dropdown.val();
})
I was only able to get the page title since this combobox now has an input element that's missing IDs, like this one:
<input id="components-form-token-input-0" type="text" class="components-combobox-control__input components-form-token-field__input" value="Page Name Here">
I have also tried doing an Ajax, to retrieve the ID using get_page_by_title() but it does not always work because pages might have the same title and editor also adds dashes and spaces in names for hierarchy levels.
How can I get the associated ID of the page selected in the Parent Combobox on change?
After some time reading the Editor Documentation I found the proper solution. This is how you can listen to changes and get the id of the Parent Combobox select in the WP Editor:
wp.data.subscribe( function () {
var newParent = wp.data.select('core/editor').getEditedPostAttribute('parent');
console.log(newParent);
} );
wp.data.subscribe is called every single time a change occurs in the current state while editing posts in the editor, so the listener function is called every single time. We can avoid that with a simple variable check when there is an actual change to the field we want. It behaves as Redux subscribe without unsubscribe and only one listener.
To also check for the current post type we are editing we can use getCurrentPostType:
wp.data.select('core/editor').getCurrentPostType();
This is the full code for this problem for future reference:
if (wp.data.select('core/editor').getCurrentPostType() == 'cpt_name') {
const getPostParent = () => wp.data.select('core/editor').getEditedPostAttribute('parent');
// set initial parent
let postParent = getPostParent();
wp.data.subscribe(() => {
// get current parent
const newPostParent = getPostParent();
// only if parent changes
if( postParent !== newPostParent ) {
// Do what we want after parent changed
toggleFields();
}
// update the variable
postParent = newPostParent;
});
}

Dynamically loaded JS needs to be clickable just like it's in the html

My page fires off an ajax query, where the MySQL Db is queried and the results are returned. (all successful).
Those results are formatted for output as a shopping gallery/catalogue and also as an accordion filter menu. So I can filter the shopping catalogue display. eg say I want to see only items that are red.
All is working so far.
My problem is with the filter accordion menu - dynamically created in js.
When I click on any selectable item in the tab-content, nothing happens. This means the parameter that should be sent, isn't being sent.
If I hard code the accordion filter or even load it with my server-side language, into the html directly, the filtering does send off the parameter and so the shopping catalogue is adjusted accordingly but, in that scenario, I am unable to dynamically change the filter menu.
I think the code I shall post below is the relevant code that recognises changes in the originally loaded content and fires off the ajax but (I think) it doesn't understand any changes to textboxes in the dynamically loaded content.
Please help me to understand what I need to add that will make dynamically loaded content fire-off to the ajax calls.
var $checkboxes = $("input:checkbox");
function update_nav_filter(opts) {
$.ajax({
type: "POST",
url: "/php-queries/product-filter-query.php",
dataType: 'json',
cache: false,
data: {
filterOpts: opts
},
success: function(records) {
//console.log(records);
//alert('SUCCESS!');
// alert(records);
$('#filters_div').html(makeFilter(records));
}
});
}
$checkboxes.on("change", function() {
//alert('there is a change is checkbox status'); // working on page load but not when any checkbox is clicked-on
var opts = getCatalogueFilterOptions();
updateCatalogue(opts);
update_nav_filter(opts);
});
$checkboxes.trigger("change");
Any help greatly appreciated.
I have created an event listener.
Following page-load, I select an item in the JS generated nav filter. eg pedal_bins in the sub_category section. I am then shown a display of pedal_bins. :)
Then I select 'kettles', another sub_category but I can only see the last sub_category that I click on. The pedal_bins disappear.
How best can I build and remove items with a single click? Store in a session parameter and then
a. remove the latest click if it matches whats in the session
b. add the latest click if its not already in the session
Then submit whatever the array is at that stage?
Or, is there a better way to run this?
Here's the listeneer
enter code here
document.getElementById("filtering_div").addEventListener("click",function(e) {
// e.target was the clicked element
if (e.target && e.target.matches("input")) {
var parameter = e.target.id;
//console.log("Anchor element", parameter , " was clicked" );
var opts = getCatalogueFilterOptions(parameter);
console.log(opts);
// update_nav_filter(opts);
updateCatalogue(opts);
}
});
You have a "delegation" problem. When you create a dynamic element, in order to be able to act on the newly created element, you have to reference it as a child element that was originally loaded with the DOM.
For example, if you have an element called <div id="top"></div> and you create a dynamic element, let's say <button id="test">Click</button> in there, you'll have to refer to that div when adding an event listener.
$("#top").on('click', '#test', function(){
//event related code goes here.
});
Here is a fiddle I created that explains the whole thing with some examples.
If you have any questions about it, please let me know.

Dojo: for each row in a grid, have a button that when clicked shows more information from the data store

This is proving to be surprisingly difficult.
Suppose I have a grid that displays the name and size of files.
Information is loaded from a JSON file into an instance of dojo/store/Memory and then key attributes presented in the grid. How would I include a button on each row of the grid, that when clicked, displays more attributes about the file? These attributes are stored in the dojo/store/memory.
Right now I have a row like this in the grid:
{name:"More", field:"id", formatter: buttonFormatter, datatype:"string", noresize: true, width: "120px"}
And I attempted to pass the ID to a button using the formatter:
var buttonFormatter = function(inValue){
var newButton = new Button({
label: "Details",
onClick: function(inValue){
alert("More information about " + inValue + " goes here");
}
});
return newButton;
}
This doesn't work however.
The difficulties, as far as I can tell, are:
1) Associating each specific button with a specific file from the store
2) Giving the onClick javascript access to data from the store
Thanks for your help!
Tristan
You can use dojo-data-type-event attach point to do the operation. The corresponding method in the grid widget instance will show your more attributes in different style like tooltip,append,dialog and etc as you need
Not sure if this might helps you, but have a look at it.
In this example there's an onclick-Event on a button to zoom to the clicked row.
https://developers.arcgis.com/en/javascript/jssamples/fl_zoomgrid.html
Regards

YUI Datatable Drag and Drop together with Cell Editor

I have a problem with YUI (2) Datatable and Drag and Drop combo. I have a table of items, one of them is item description which I made editable (and saveable) with YUI's TextboxCellEditor. I also made the rows draggable (so I can drop them to another container).
But I'm stuck with two items:
- I can only get DnD by clicking on the second column (the first one does not work)
- I can only get it to work on the second attempt since initialization.
Here is a snipet from my JS (simplified):
nameFormatter = function (elCell, oRecord, oColumn, oData) {
var link = '/share/page/site/' + Alfresco.constants.SITE + '/document-details?nodeRef=' + oRecord.getData('nodeRef');
elCell.innerHTML = '<span>' + oData + '</span>';
};
descFormatter = function(elCell, oRecord, oColumn, oData) {
elCell.innerHTML = '<pre class="desc">' + oData + '</pre>';
};
columnDefs = [
{key: "name", label: "Name", sortable: true, formatter: nameFormatter, resizable: true}
, {key: "description", label: "Description", sortable: true, formatter: descFormatter, editor: new YAHOO.widget.TextboxCellEditor(), resizable: true}
];
this.mediaTable = new YAHOO.widget.DataTable(this.id + "-media-table", columnDefs, this.dataSource, {
MSG_EMPTY: "No files"
});
// now we want to make cells editable (description)
var highlightEditableCell = function(oArgs) {
var elCell = oArgs.target;
if(YAHOO.util.Dom.hasClass(elCell, "yui-dt-editable")) {
this.highlightCell(elCell);
}
};
this.mediaTable.subscribe("cellMouseoverEvent", highlightEditableCell);
this.mediaTable.subscribe("cellMouseoutEvent", this.mediaTable.onEventUnhighlightCell);
this.mediaTable.subscribe("cellClickEvent", this.mediaTable.onEventShowCellEditor);
this.mediaTable.subscribe("editorSaveEvent", this.saveDesc);
this.mediaTable.subscribe('cellMousedownEvent', this.onRowSelect);
The saveDesc function is simple Ajax call to save that items' description.
Here is the onRowSelect function:
onRowSelect = function(ev) {
console.log(" == method onRowSelect");
var tar = Event.getTarget(ev)
, dd
;
dd = new YAHOO.util.DDProxy(this.getTrEl(tar));
dd.on('dragDropEvent', function(e) {
YAHOO.Bubbling.fire('myCustomEvent', { target: e.info, src: tar});
dd.unreg();
});
};
If I just click on desc, I get the text editor, if I click on name, I get the link open.
Like I said, when I mouseDown on the second column (description), in first attempt I get nothing. Then I click and hold the second time, and this time it works (I get a DDProxy and I can Drag and drop it to the target, everything works there).
And the other issue is that when I click and hold on the name column, I don't get the DDProxy (I get my onRowSelect event and the correct row).
What am I doing wrong here?
UPDATE: Resolved the first issue by using Satyams answer - removing the formatter for my cell with link.
The second issue (only on the second click) was resolved because I added the missing dd.handleMouseDown(ev.event) in my onRowSelect function.
Dav Glass, who wrote DD, has this example in his page: http://new.davglass.com/files/yui/datatable4/ I used it in my example: http://www.satyam.com.ar/yui/2.6.0/invoice.html and it works just fine, though it is somewhat more involved than you have there. I'm sorry I cannot help you more precisely with your issue, D&D is not my string point but I hope the examples might help.
One reason for your problem might be that link in the cell. This is not a good idea, whether you have DD or not. In general, the recommended way to deal with this is to listen to the cellClickEvent and if the column of the cell that got clicked is the one that 'navigates', you build the URL based on the information in the record clicked and then navigate or do whatever you want with it. This allows the DataTable to render much faster, as it needs no formatter and, in the odd event that someone does click the cell, then and only then you bother to make the calculations. The size and number of DOM elements on the page also goes down.
Likewise, with the other cell with the pre-formatted tag, you can easily avoid it. The cells in each column in a DataTable gets a CSS class name made from the "yui-dt-col-" prefix and the 'key' value of the column (for example: yui-dt-col-description). Thus, you can simply add a style declaration for that CSS class name and spare yourself the formatter. Likewise, for highlighting the editable cells, how about defining some style for the .yui-dt-editable:hover selector? I've never done it myself but I imagine it should work.

Knockout options/value bindings javascript after applyBindings does not execute

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.

Categories