fiddle: https://jsfiddle.net/aa1z1m8t/3/
I'm using a library that allows the creation of treeviews as a bootstrap component, however I think this is more of a JS question than a library-use question.
I want to change title of the li element (tree node) upon selection, but the applied changes simply do not show! As if the element doesn't refreshes.
I've tried using the library's event, I've tried using the jQuery's click event (both, click and on variants), but to no avail. I've also tried various reflow tricks.
How can I force a refresh?
Note that the treeview is being generated and appended to DOM via JS.
To sum up: I wanted to change the node's title on selection, but changes aren't applied for some reason.
i tried to understand your problem, but i am not completely sure.
https://jsfiddle.net/aa1z1m8t/11/
function CreateTreeView() {
$('#tree').treeview({
'data': treedata,
'onNodeSelected': function(event, data) {
alert(data);
}
});
}
I build a function to create the treeview and call it every time a event is fireing.
Related
Question:
I am trying to build a dynamic form using jQuery. There are a few standard html form inputs in a row in addition to a CSS stylized "hidden checkbox" toggle button. (Example)
The first row is statically coded, and there is a button to add more rows to the form for batch submissions. JQuery applied to the .on(click) event works perfectly with the static content, but newly appended form rows ignore the binding. Even jsfiddle's dynamic display doesn't appear to function, though it is possible my fiddle example has a bug that my working copy doesn't have. (Fiddle)
/* activeToggle is the selector for the container and descendants,
// .toggleHappy is the hidden input element within activeToggle */
$(activeToggle).on("click", ".toggleHappy", function(e) {
e.preventDefault();
$(this).val(($(this).val() == 0) ? 1 : 0);
console.log($(this).val());
});
I have researched and found the common mistake of using .click() instead of delegating using .on(click, selector, fn()) and am thus using the latter now.
What is frustrating is I have another .on(click) that IS working with the dynamic content. (the remove function) So, I was hoping another pair of eyes might help me find out what my mistake is. I know this is very similar to other questions on the basic subject, but I have read quite a number of those discussions first, and have applied many of them to get where I currently am.
Updates:
I tried what Madhavan suggested and it does in fact work, but as expected, only for the first-child. So dynamically added rows are not pointed to. Thanks for the fast look. I feel like it might be a selector/scope issue, but whats weird is that once the page is loaded, I can type this directly into console and it works?
//this works run from console, but doesn't fire from a real click?
$(".theContainer .data .switch .toggleHappy").first().click();
ANSWER I have been working on another project in the interim and it is starting to look like .on(event, selector, fn) is not working at all for dynamically added items. But, I had a breakthrough! The other project was slightly simplified, and I found the following:
//.theContainer is static
//.data .switch .toggleHappy is the dynamic chain created
//does not delegate and bind dynamically
$(".theContainer").on("click", ".data .switch .toggleHappy", function() {});
//DOES work!
$(".theContainer").on("click", ".toggleHappy", function() {});
It would appear that a selector like .path .to .element only works well on existing static content, while .element allows .on() to be bound and delegated properly for dynamically generated nodes. See the updated fiddle.
The part that confused me was that hopping into the console and referencing dynamic elements with the full selector DID work on dynamic elements, but the events weren't delegated to them. Thanks again for the eyes that looked over this question, hope it helps someone else, because I still haven't found this on the web yet.
It appears that delegating jQuery events with .on() will only work on static content when the selector used within .on() is a list of consecutive elements. In my code, I had a single container which was static, I delegated an event to it referencing multiple elements between the container and the destination elements. It would work locally for any number of statically identified elements, but any dynamically added ones would ignore the bindings. It also would throw no errors, and it WOULD respond to lines of script executed within the console directly, using the same selector chaining as the function. I found the following:
//.theContainer is static
//.data .switch .toggleHappy is the dynamic chain created
//does not delegate and bind dynamically
$(".theContainer").on("click", ".data .switch .toggleHappy", function() {});
//DOES work!
$(".theContainer").on("click", ".toggleHappy", function() {});
It would appear that a selector like ".path .to .element" only works well on existing static content, while ".element" allows .on() to be bound and delegated properly for dynamically generated nodes. See the updated fiddle.
The part that confused me was that hopping into the console and referencing dynamic elements with the full selector DID work on dynamic elements, but the events weren't delegated to them. Thanks again for the eyes that looked over this question, hope it helps someone else, because I still haven't found this on the web yet.
$(activeToggle).on("click", function(e) {
e.preventDefault();
$(":first-child",this).val(($(":first-child",this).val() == 0) ? 1 : 0);
console.log($(":first-child",this).val());
});
I made a change like this and works fine. But I'm not sure why it is not triggering for '.toggleHappy' instead.
I have a series of folders that are represented as links using a VueJS for-loop, wit data pulled from API. For each of those links, I am using a library called x-editable to allow for the editing of the names. Essentially, when you click on the link with defined attributes (assuming you instantiate via editable(), it will bring up a pop-over).
I find that if I create a dummy link (outside of the for loop) and include the instantiation in a document.ready block, it works just fine:
EDIT: Note that the ready: function() is a custom document.ready function, defined in a Vuejs router.
ready: function() {
jQuery.fn.editable.defaults.mode = 'popup';
jQuery('.editable').editable();
},
However, none of the dynamically generated links work when they are clicked. My guess is that jQuery is simply not detecting them, as they were not made when the document was loaded.
I tried to call editable after the data was received and assigned to Vue:
//Folders
this.$http.get('/api/folders').then(function(response) {
this.state.folders = response.data;
jQuery('.editable').editable();
});
However, it seems that this doesn't work either. I read that you can bind events using .on() which will work with generated elements. However, .editable() isn't really an event (I think). Is there a way to get around this?
I have a set of links with a class app-context-link on my page – just some <a> menu elements.
They are generated when the page is loaded from some data that the page receives from a JSON.
I then apply the following on click jQuery function, to make sure that when a user clicks on one of those elements, a certain procedure is performed:
$(".app-context-link").on('click', function(e) {
e.preventDefault();
// do something
}
The problem is that when the user clicks on one of the items, I want to highlight the item they clicked, perform some action on the JSON, and then return a new menu to the user that has other elements of the same class app-context-link – in this case the "old" onclick function does not apply to the newly added items, right? And then I can't get them to behave in the same way because of that.
Does anyone have an idea how I could resolve it?
I know I probably have to rewrite everything very carefully with callbacks, etc. but maybe there's an easier solution already inside jQuery and I'm just missing something?
And as a bonus track – if I decided to leave the menu as it is and just to highlight the element clicked (through appending a class), how would I do that? Sorry if that last question sounds stupid, but I'm a novice and feel a bit confused...
Thank you!
You need to delegate event, e.g:
$(document).on('click', ".app-context-link", function(e) {
e.preventDefault();
// do something
});
Now selector will be filtered on each click.
document is an example, usually, you'd prefer to bind it to closest static container
function bindLink() {
$(".app-context-link").click(function() {
// do something
});
}
Now, everytime you change your data, you can call your bind function (bindLink()).
When clicking on the text of a node beside the checkbox, I'd like for the checkbox to toggle its checked state. Ordinarily this is done with a <label for="whatever"></label>. But since jsTree doesn't use real checkboxes, how might this be done?
When creating the tree with $('#mytree').jstree({'plugins':['checkbox']}), if I put .delegate("a", "click", function (event, data) { $(event.target).find('.jstree-checkbox').click() }) at the end, it works. But there is a discernible delay.
Hence, I pose the question, what is the best way to check the box when clicking its corresponding text?
I agree with the click handler technique you're using. I don't see the delay mentioned, but that could be because I'm not posting anything back to the server.
If the checkbox is purely visual, then perhaps the class can be modified directly. This should be must faster than throwing another click event.
$(event.target).parent("li:first").toggleClass("jstree-unchecked").toggleClass("jstree-checked");
The checkbox plugin for jstree does appear to perform other actions when checking / unchecking the node. I believe the following should do what you're looking for:
$(function(){
// Initialize jstree
var $tree = $('.tree-target').jstree({
"plugins": ["checkbox"]
});
// Bind an event to the anchor tag within each tree entry
// Note: '.on' is used here as this will ensure that any
// dynamically-generated entries will also use this 'click'
// event.
$tree.on('click', 'li.tree > a', function (e) {
e.stopPropagation();
// Find the first parent 'tree' element
var $node = $(this).parents('li.tree').eq(0);
// Toggle the state of the current 'tree' element
// Note: The third parameter (in this case 'toggle')
// can be any value other than true or false
$tree.jstree('change_state', $node, 'toggle');
return false;
});
});
On a side note, I believe the reason your approach led to a significant delay could have to do with you binding the click event to every single <a/> tag on the page. This would result in significant overhead when trying to find the appropriate event targets.
I am using Flowplayer's jQuery Tools framework (specifically the tooltips plugin) in a table, in addition to jQuery UI calendar.
Each row of the table has the ability to insert a row above and below it.
When doing this I am cloning the clicked object (events and objects) and inserting it directly above or below.
After adding a new row, I refresh the table, generating new id's for my elements, reinitializing the datepicker, and attempting to reinitialize the tooltip.
I am searching for a way to destroy it altogether from the instance and reapply it.
I am looking for something similar to the datepicker('destroy') method.
$j($editRow).find('input.date').datepicker('destroy').datepicker({dateFormat: 'mm-dd-yy', defaultDate : defaultDateStr});
I have already attempted to :
to unbind the mouseover and focus events : when reinvoking tooltip, it automatically goes for the object it was made from.
hide the tooltip DOM element, remove the tooltip object from the target, and reapply it. The same thing happens as (1)
Is there way I can create a destroy method myself?
I tried kwicher's method, and could not get it to work. Although I was trying to alter the minified code, and I'm not entirely sure I found the right place to make the change.
I did, however, get this to work. ValidationFailed is a class I am applying to all the input fields that are also having tooltips applied to them.
$('.validationFailed').each(function (index) {
$(this).removeData('tooltip');
});
$('.tooltip').remove();
I tried this several different ways, and this was the only combination that allowed me to add additional tool tips post-removal, without preventing the new tooltips from working properly.
As best I can tell, the tooltip class removal handles getting rid of the actual tooltip divs, whose events are also wired up directly. The .removeData allows the tooltip to be re-bound in the future.
Building on your ideas and Tom's answer, I found that three things are necessary:
remove the 'tooltip' data from the tooltip target element
unbind event listeners from the tooltip target element
remove the element (assuming you're using this tooltip approach to allow for arbitrary HTML in your tip)
So, this simple function should do the trick. Just pass it a jQuery object containing the target elements of the tooltips you want to destroy.
function destroyTooltips($targets) {
$targets.removeData('tooltip').unbind().next('div.tooltip').remove();
}
If you still need it you can do as follows:
- in the tooltip implementation file add the following function
destroy: function(e) {
tip.detach();
}
somewhere in :
$.extend(self, {
...
I have after the last native function.
Then when you want to remove the tip, fire:
$(.tip).data('tooltip').destroy();
It should do the trick
K
if($element.data('ui-tooltip')) {//if tooltip has been initialized
$element.tooltip('destroy');
}
Maybe it's too late... ;-)
But here you can find all methods of 'tooltip': http://www.w3schools.com/bootstrap/bootstrap_ref_js_tooltip.asp
I leave the tip for someone who could pass by, having the same problem: dealing with different 'tooltip' actions/objs.