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;
});
}
Related
I have a form where the user can dynamically add or remove sets of fields. For each set of fields, when the user enters/changes a value in the upc[] text input I want to make an Ajax query and populate the corresponding desc[] text input. I can capture the change event, but have not been able to read or modify the dynamically create desc[] field:
This snippet does not have the Ajax call as for now I just want to know I can set desc[x].val(). I have tried to associate the dynamic field with a parent element that existed when the DOM was created...but still no luck.
$(document).on('change', '.upcScan', function(){
var upcIdx = $(this).index('.upcScan');
var upcVal = $(this).val();
alert ("The current index is "+upcIdx+" and the value is "+upcVal);
var descName = "desc["+upcIdx+"]";
var descVal = $("#addClient input[name='"+descName+"']").val();
alert("desc field is "+descName+" and value is "+descVal);
});
The code above returns null. If I try to set the val nothing happens.
What am I missing?
I have a form with multiple select menus generated with Select2 (version 4) where the id value of each select element is set dynamically. I'd like to find the id of the select element the user clicks on.
I can get this to work
$('.js-example-tokenizer-ajax-data').on('select2:open', function (evt) {
myValue = $(this).attr('id');
});
But I need to use myValue as a parameter for data inside an ajax call so an option getting the id of the active select2 element is needed. I've seen posts that suggest var selectedEle = $(document.activeElement) but I don't know how to get the id from there.
UPDATE
It seems I can include this as the value for the data parameter
data: getSelectedElement(function() {
return JSON.stringify({variable: myValue})
}),
with the function as
function getSelectedElement(callback) {
$('.js-example-tokenizer-ajax-data').on('select2:opening', function (evt) {
myValue = $(this).attr('id');
callback();
});
}
But there are still some timing issues since the ajax seems to fire before a select element is clicked since when I load the page I get an error 'NoneType' object has no attribute '__getitem__' I gather since there was no value for myValue when the page loaded.
Are there other options to get the id of the selected select2 element? Alternatively, are there ways to sort out the timing issue?
If var selectedEle = $(document.activeElement) does in fact get the element that you want you can simply do document.activeElement.id.
Update based on poster's update:
In a different stack overflow answer someone said this.context will give you the correct element, in which case this.context.id would give you the id.
I've got three dropdown menu's which are dynamically filled from the database each time I select an option in the previous dropdown menu.
Now I want to access the values in these dropdown menu's, so that I can build a SQL-query somewhere later.
I've used the following code to access the HTML elements:
$( window ).load(function(){
var e = document.getElementById("slctTable");
var slctTableValue = e.value;
console.log(slctTableValue);
});
This code only works the first time the page loads, so when I mess around with the dropdown menu's, nothing changes.
What I want now, is that each time I select a value in the dropdown menu, it updates the slctTableValue variable.
Bind change event to the drop-down with jquery, then this event will fire whenever there is a change happened on the selected value.
$("#slctTable").change(function() {
var slctTableValue = $(this).val();
console.log(slctTableValue);
});
You can detect change event like this and update value:
document.getElementById('slctTable').addEventListener('change',function(){
var e = document.getElementById("slctTable");
var slctTableValue = e.value;
console.log(slctTableValue);
});
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 have a dropdown select list on my page of class="TypeFilter".
I have a jQuery event that fires when a value in that list is selected.
$(".TypeFilter").change(function()
{
// Extract value from TypeFilter and update page accordingly
));
I now have to add another list to the page, and I want to implement functionality which will prevent the .change(function() from running unless both are selected.
In both lists the first option in the list is some text instructing the user to select one of the items, so I was thinking of just writing some logic to test that both lists have a selected index greater than 0.
I think this is a touch unclean though, especially considering that other pages that have a TypeFilter use the same logic.
Is there any nifty functionality in jQuery that can do this?
edit I should specify that the user needs to be able to update the page by selecting either dropdown, so I can't put the onchange on the second element and test that the first element has a selected value, as suggested in one of the answers
If you bind the same event to all dropdowns, you can get a collection of all the dropdowns and check that all of them are selected. Example:
$('.Dropdown').change(function(){
var elements = $('.Dropdown');
if (
elements.filter(function(){
return this.selectedIndex > 0;
}).length == elements.length
) {
// all dropdowns are selected
}
});
As you partly mention, put the onchange on the second element and test that the first element has a selected value before you fire off any logic.
Use bind instead, and as the eventdata, send a function that checks that either that both are selected or that the other is selected. Untested code:
function checker() {
// test your conditions
}
$(".TypeFilter").bind('change', {test: checker}, function(event)
{
if (event.data.test && event.data.test()) {
// Extract value from TypeFilter and update page accordingly
}
));
This way the other pages that use the same function will not notice any changes.