I am trying to get some contenteditable elements working. Obviously this is incredibly easy with just a simple HTML5 attribute, but I want to be able to toggle the amount of elements with the attribute and also toggle the attribute itself. For example, my starting element is this <article class="column contentEditable"> and then the class of contentEditable is used to toggle the contenteditable attribute. But because I am duplicating this element an amount of times based on what the user selects - I need to run the .focus() action as a function which is then called when some more articles are added. With me so far? Hope so.
Here is the jQuery I have so far (bearing in mind another function sets the class contentEditable to have the attribute contenteditable)
// content edittable
function makeEditable(action){
$('.contentEditable').focus(function(){
$(this).addClass('active');
$(this).prepend('<div class="toolbar" contenteditable="false">TEST</div>');
});
$('.contentEditable').blur(function(){
$(this).removeClass('active');
$(this).remove('.toolbar');
alert('test');
});
}
To a certain extent this works perfectly, however because an article may have already been there when this DOM call was issued before, it means that it's running twice or more (depending on how many times I've changed the option in the select. How on earth can I get the function to only run once per item, i.e. not stack.
Hope this all makes sense, pretty difficult to explain.
I think what's happening here is that you are calling the makeEditable function everytime the user is selecting an element to edit (if I understand your workflow right). If that's happening you're adding a new focus and blur event every time they do and that will cause the event to fire multiple times.
What I recommend is something like this:
function addElement(containerElement) {
// containerElement is a string with the jQuery selector of the parent element
var el = $('<article class="column contentEditable"></article>').appendTo(containerElement);
el.focus(function(){
$(this).addClass('active');
$(this).prepend('<div class="toolbar" contenteditable="false">TEST</div>');
});
el.blur(function(){
$(this).removeClass('active');
$(this).remove('.toolbar');
alert('test');
});
}
function toggleEditable(el) {
// here el is a string with the jQuery selector of the element
$(el).toggleClass('contentEditable');
}
It was a simple case of having a process class on it to only run it once, each time the .focus is run it removes the process class. Pretty simple really, fresh eyes helped after a break. Thanks.
Related
I have a function that dynamically creates div elements based upon whatever input is given, and lets them choose certain items by clicking on each div. I have it so that if the div is clicked, a function (named checkToggle) is called that makes it looks like it is selected and adjusts some related variables. There is a checkbox in the div element that is toggled by this function (hence its name). Long story short, I had to jump through some hoops to get it to work, most of which I don't even remember. Please don't ask me about that.
The point of this question is this. I initially used the following JavaScript code to run the function when the checkbox was clicked. It was assigned by the main function, which created these div elements using a for loop.
document.getElementById(`${itemID}-checkbox`).onclick = function() {
checkToggle(`${itemID}-checkbox`);
};
This works, but I wanted to try to convert all of my onClick functions to JQuery. Here is the JQuery alternative I created.
$(`${itemID}-checkbox`).on(`click`, function() {
checkToggle(`${itemID}-checkbox`);
});
While the code itself seems to be fine, it does not work. It seems as if JQuery functions cannot be created like this in a for loop or something. It is applied after the element is created and put in its place, so I don't think it has anything to do with the element not being ready. I am also having the same issue with 2 other similar cases. Any idea as of why this isn't working?
Let me know if more information is needed and if so, what kind of information is needed.
You need to update the selector to Target HTML id using the # character. Simply prepend the character to the query:
$(`#${itemID}-checkbox`).on(`click`, function() { checkToggle(`${itemID}-checkbox`); });
It would also apply to DOM methods querySelector or querySelectorAll as well.
Hopefully that helps!
I am still a bit new to JS & JQuery, so please excuse what may be a simple and stupid question.
Background:
I have a div on my page that holds several divs (#idle-variable). On click of the top level div, it basically shows the other divs (#addvariable). Nothing more than display: none; and .show(). Easy. On another action within that div (change of drop down), I essentially want to inject/insert that top level div (#idle-variable) underneath the first instance.
Issue:
Essentially, the .click function is not working on my newly inserted div. This may be because the two div's share the same ID, BUT I have a sneaky suspicion that it's not recognized in the DOM. A friend of mine said something about I have to "re-run" my jquery in order for it to be readable in the DOM.
Question:
How can i make this work properly? I want to be able to add a dynamic number of these idle-variables to the page and I need to make sure my .click function works for all added DIVS.
$(function(){
$('#idle-variable').click(function(event) {
$("#addvariable").show(400);
});
});
//create variable in db & show value entry
$("#variabletype").change(function() {
$("#varholder").css("display", "inline-block");
$.ajax({
type: "POST",
url: "/myphpfile.php",
data: {"variabletype": $("#variabletype").val()},
success: function(){
$( "#idle-variable" ).after("<div id="#idle-variable>content</div>");
}
});
});
Well to make the code work it would need to use on and ids are only supposed to be on one element. If it can be on the page multiple times you need to use classes.
$(document).on("click,'#idle-variable', function(event) {
$("#addvariable").show(400);
});
you should be using classes
$(document).on("click,'.idle-variable', function(event) {
//$("#addvariable").show(400); //not sure how this relates to the clicked element.
$(this).find(".addvariable").show(400); //if it is a child
});
You also have a typo in your code with quotes.
The ID based selector will be applied to the first element only.
See the example here http://jsfiddle.net/9GN2P/2/
If you are looking to bind same event handler to multiple elements, definitely go with the class based approach, instead of ID based approach.
And, you are expecting event handler to work with dynamically created elements as well. If you are using older versions of jquery, use the live method like
$('yourselector').live('click',function(){
});
Since live is deprecated and if you are in a new version, use the 'on' method
$('containerselector').on('click','yourselector',function(){
});
Editing to answer your comment:
To create dynamic element and append to DOM, you can follow the bellow pattern. Here, I will create a DIV with id "newID", class "newClass", content "NEW DIV!!" and a click event handler for it. And it will be pushed into another div with id 'containerID'
$('<div />',{
id:'newID',
'class':'newClass',
text:'NEW DIV!!',
click:function(){alert('hi');}
})
.appendTo('div#containerID');
This is just a demo.
For each checkbox on the web page, I replace it with a slider that I borrowed from jsfiddle.net/gnQUe/170/
This is done by going through the elements when the document is loaded.
Now the problem is that when more content is loaded via ajax, the new checkboxes are not transformed.
To solve the problem, I used AjaxComplete event to go through all the elements again and replace the checkboxes with sliders.
Now the problem happens that elements that were already replaced, get two sliders. To avoid that I check if the checkbox is hidden and next element is div of class "slider-frame", then don't process the re-process the element.
But I have a lot of other such controls as well, and I am presume I am not the only one that has this problem. Is there another easy way around it?
There exists jQuery live/on( http://api.jquery.com/on/ ) event but it requires an event as an argument? whereas I would like to change the look of my controls when they are rendered.
Another example of the same problem is to extend some controls that are loaded via ajax with jQuerys autocomplete plugin.
Is there a better way to accomplish this other than changing some attributes on the element.
To summarize, on document load I would like to process every element in DOM, but when more elements are loaded via ajax then I want to change only the new elements.
I would assume that when the element's are transformed into a slider, a class is added to them. So just add a not clause.
$(".MySelector").not(".SomeClassThatSliderAddsToElement").slider({});
So in the case of your code do something like this
$('.slider-button').not(".sliderloaded").addClass("sliderloaded").toggle(function(){
$(this).addClass('on').html('YES');
$('#slider').val(true);
},function(){
$(this).removeClass('on').html('NO');
$('#slider').val(false);
});
Since you said you do not want to add anything else, how about you change the toggle function to click.
$(document).on("click", ".slider-button", function(){
var elem = $(this);
elem.toggleClass("on");
var state = elem.hasClass("on");
elem.text(state?"YES":"NO");
elem.parent().next().val(state);
});
Running fiddle: http://jsfiddle.net/d9uFs/
I have a form that I am trying to alter with jQuery. Basically, my form has two elements and I need to change the value of the first option in each of them. However, there is an "add more" option that uses AJAX to dynamically generate another element that also needs changed. This add more button can be clicked an unlimited amount of times.
Right now I have this:
$(document).ready(function(){
$("#myname-0-field option:first").val("None");
$("#myname-1-field option:first").val("None");
});
This works fine, but once the "add more" button is clicked, I have more elements called "#myname-2-field", "#myname-3-field", "#myname-4-field" etc. These obviously aren't affected by adding another line into my jQuery as the document has already loaded when they are added.
So the real question is, can someone point me in the right direction of writing a function that can react when the new element is added and change it. If possible, I'm also looking for the function to be aware and look for "#myname-X-field option:first" for tidyness.
use live() function
Then using each function set value
From the jQuery API look live function
Maybe you could add class to your element, so that finding particular element would be easier and it would not add event to other similar elements.
In the example I have a Li with class
$('li.myClass').live('click', function() {
$(this).val(); // this is the getter for clicked value
$(this).val("some_value_here"); // this is the setter for clicked value
});
Now you can add more elements (that has myClass class) and it will have a click event.
Btw. if you know that all elements are inside some container (div for example) then you can write more efficient jQuery using delegate.
$('#container_id').delegate('li.myClass', 'click', function () {
});
This is more efficient because it looks your new elements only under "containter" not from the whole DOM structure.
I want this webpage to highlight certain elements when you click on one of them, but if you click anywhere else on the page, then all of these elements should no longer be highlighted.
I accomplished this task by the following, and it works just fine except for one thing (described below):
$(document).click(function() {
// Do stuff when clicking anywhere but on elements of class suggestion_box
$(".suggestion_box").css('background-color', '#FFFFFF');
});
$(".suggestion_box").click(function() {
// means you clicked on an object belonging to class suggestion_box
return false;
});
// the code for handling onclicks for each element
function clickSuggestion() {
// remove all highlighting
$(".suggestion_box").css('background-color', '#FFFFFF');
// then highlight only a specific item
$("div[name=" + arguments[0] + "]").css('background-color', '#CCFFCC');
}
This way of enforcing the highlighting of elements works fine until I add more html to the page without having a new page load. This is done by .append() and .prepend()
What I suspected from debugging was that the page is not "aware" of the new elements that were added to the page dynamically. Despite the new, dynamically added elements having the appropriate class names/IDs/names/onclicks ect, they never get highlighted like the rest of the elements (which continue to work fine the entire time).
I was wondering if a possible reason for why my approach does not work for the dynamically added content is that the page is not able to recognize the elements that were not present during the pageload. And if this is a possibility, then is there a way to reconcile this without a pageload?
If this line of reasoning is wrong, then the code I have above is probably not enough to show what's wrong with my webpage. But I'm really just interested in whether or not this line of thought is a possibility.
Use .live to "Attach a handler to the event for all elements which match the current selector, now and in the future". Example:
$(".suggestion_box").live("click", function() {
// means you clicked on an object belonging to className
return false;
});
Also see .delegate, which is similar.
Since the .live() method handles events once they have propagated to the top of the document, it is not possible to stop propagation of live events. Similarly, events handled by .delegate() will always propagate to the element to which they are delegated; event handlers on any elements below it will already have been executed by the time the delegated event handler is called.
from the jQuery documentation =)
(only to explain better why #karim79 also suggested the delegate method ;P )