Jquery result in its relative div - javascript

I am facing a problem that i have multiple DIVs with almost same ID but having increments from 0 to any number in the end, I want to use this username check function for every different username field and show its results in its specific related div. I tried all the possible ways but its not working.
Here is my Fiddle
Here is my Code
$(document).ready(function() {
$('[id^=Loading]').hide();
});
function check_username(){
var username = $("[id^=username]").val();
if(username.length > 1){
$('[id^=Loading]').show();
$.post("username-Check.php", {
username: $('[id^=username]').val(),
}, function(response){
$('[id^=Info]').fadeOut(2100);
$('[id^=Loading]').fadeOut(2100);
setTimeout("finishAjax('Info', '"+escape(response)+"')", 2000);
});
return false;
}
}
function finishAjax(id, response){
$('#'+id).html(unescape(response));
$('#'+id).fadeIn(2000);
}

Incremental/dynamic id attributes are almost always an anti-pattern and should be avoided where possible as they create more problems than they solve.
A much better solution would be to use DOM traversal to find the elements related to the one which raised the event - in your case the blur on the input.
To do this, firstly use unobtrusive event handlers instead of the outdated on* event attributes. Then change the id attributes to classes. To find the elements, use the this keyword to reference the element that raised the event, then prev() and prevAll().first() to find the required element by its class. Finally, provide an anonymous function to setTimeout() over hacking together a string to be run through eval(). Try this:
<div class="info"></div>
<span class="loading"></span>
<input class="username form-control" type="text" name="txtengine" placeholder="914899" value="" /><br>
<div class="info"></div>
<span class="loading"></span>
<input class="username form-control" type="text" name="txtengine" placeholder="914899" value="" /><br>
$(document).ready(function() {
$('.loading').hide();
});
$('.username').on('blur', function() {
var username = $(this).val();
if (username.length) {
var $loading = $(this).prev('.loading').show();
var $info = $(this).prevAll('.info').first();
$.post("username-Check.php", {
username: username,
}, function(response) {
$info.fadeOut(2100);
$loading.fadeOut(2100);
setTimeout(function() {
$info.html(response).fadeIn(2000);
}, 2000);
});
}
})
Working example
Note that the example in the fiddle had the AJAX request logic amended to fit jsFiddles' JSON response logic, but the functionality is the same.

Before I start answering I would strongly suggest you to use a class and then select via class name. As it seems your case is textbook for when to use jquery class-selectors.
You cannot use the attribute selector without specifying what you are using it on. I.e. you cannot say:
$('[id^=Loading]')
you need to give the tag name, the id, or the class i.e.
$('span[id^=Loading]')
I have made a jfiddle for you:
https://jsfiddle.net/acc069me/6/

Related

Detect click on input via the name attribute

I am trying to detect when one of these inputs are clicked and do a simple display none on a div. Everything I have tried will not detect a click. I do not have control over the html.
<div class="sibling csf--button csf--active">
<input type="radio" name="setting[open_btn_icon]" value="icon_a" data-depend-id="open_btn_icon">
</div>
<div class="sibling csf--button csf">
<input type="radio" name="setting[open_btn_icon]" value="icon_b" data-depend-id="open_btn_icon">
</div>
This is the last thing of many I have tried.
document.querySelector('[name="setting[open_btn_icon]"]').addEventListener("click", function() {
alert("Hello World!");
});
Right now all I am trying to do is detect the click. I can do the rest.
I have tried with jquery. I can do what I need when there is a class or id or a name whe nit not formatted as an array value.
I think your issue is the use of the querySelector method, which will only return a single element:
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
Consider using the querySelectorAll method, which will give you a NodeList that can be iterated over using a "for / of" loop.
In the end, your code would look something like:
let nodeList = document.querySelectorAll('[name="setting[open_btn_icon]"]');
for (let node of nodeList){
node.addEventListener('click', function(){
alert('Hello World!');
}
}
Alternatively
Consider applying a single listener to the parent DIV instead <div class="sibling csf--button csf--active">, then checking to see if the element being clicked is the one you need to react to. Depending on how many elements you actually need to react to, this could potentially help with performance.
It should fix your issue
let all = document.querySelectorAll('[name="setting[open_btn_icon]"]')
all.forEach(x=>x.addEventListener("click", function() {
alert("Hello World!");
}))
<div class="sibling csf--button csf--active">
<input type="radio" name="setting[open_btn_icon]" value="icon_a" data-depend-id="open_btn_icon">
</div>
<div class="sibling csf--button csf">
<input type="radio" name="setting[open_btn_icon]" value="icon_b" data-depend-id="open_btn_icon">
</div>
Three things could be improved to your code works:
addEventListener DOMContentLoaded to guarantee that when runs document.querySelectorAll the DOM is ready;
Change from querySelector to querySelectorAll tio get all inputs;
Rewrite rule that combines to get your inputs;
document.addEventListener("DOMContentLoaded", function () {
const allInputs = document.querySelectorAll(
'[name="setting[open_btn_icon]"]'
);
allInputs.forEach((input) =>
input.addEventListener("click", function () {
alert("Hello World!");
})
);
});

Replacing widget element with a newly constructed DOM structure

<script>
(function( $ ) {
$.widget( "my.dropbox", {
errorText: function(text) {
$(this.element).next().html(text);
},
_create: function() {
var id = $(this.element).attr("id");
var customDropbox = $(
"<div class='form-group'>"+
"<label for='"+id+"'>"+getLabelFor(id)+"</label>"+
"<select id='"+id+"'></select>"+
"<div class='errors'></div>"+
"</div>"
);
customDropbox.attr("id", id);
$(this.element).replaceWith(customDropbox); // This removes original element from DOM
populateOptions(id);
},
});
}( jQuery ));
$(document).ready(function(){
$("#field1").dropbox(); //blank input field turns into a select with a label, populated options e.t.c..
$("#button1").on("click", function(){
$("#field1").dropbox("errorText", "This is a validation error message"); //throws an error saying dropbox is not initialized
});
});
</script>
<html>
<body>
<input id="field1" />
<button id="button1">Press me</button>
</body>
</html>
So I want a widget with public methods that will replace the original element with all the widget data associated with it. The problem with the above code is that the <select..> element is just a DOM element and if you call .dropbox(..) on it, it will say the widget is not initialized. Is there a way to make the select element into the widget object with the .errorText() method? All widget examples online add stuff around the original element but never replace it. As for the bigger picture, I'm trying to make a generic tool to configure forms dynamically. It's going to be all <input id="..."> in html but then javascript will query a database, get configuration for the field and turn it into a dropbox, checkbox or, say, a date picker with all the labels, validation, and other bells and whistles.
There is more than one issue with your widget code. I'll try to summarize them:
1. Copy the data
You're not copying the data to the newly created customDropbox, so before
this.element.replaceWith(customDropbox);
you should copy the data:
customDropbox.data(this.element.data());
Now the widget will remember that it was initialized.
2. this.element is gone
After
this.element.replaceWith(customDropbox);
you should update this.element so that it points to the newly created customDropbox:
this.element = customDropbox;
3. errorText message takes wrong element
Since the widgets element (this.element) is now pointing to the <div class='form-group'></div> element, the errorText function must be slightly modified to:
this.element.find(".errors").html(text);
4. id should be unique
Now, both the wrapper <div> and the <select> have the same id, which is not allowed in HTML so remove the one on the <select> tag. Luckily, <label> can work without the for attribute, just write it like this:
<label>labelForId <select></select></label>
Then to get the <select>-element, use this.element.find("select") in the widget.
Side note
`this.element` is already a jQuery element, so no need for the additional `$()` wrapping.
See this jsFiddle
function show(){
$("#field1").input({....});
}
function hide(){
$("#field1").input("hide");
}
<button onclick="show()">show</button>
<button onclick="hide()">hide</button>
i think to replace the origin element which initial dropbox() is not a good solution,
because this will force you to rely on the implemention details of jQuery ui factory,
it is easy to make a mistake or introduce bugs, sometimes harder for other people to understand your code
if jquery ui factory change the implemention in the future, you have to modify all your code to make it work
(sorry for my limit understand of jquery ui)
i think we can put the <input/> into a container and initial dropbox() on the container which inturn
replace <input/> with <select> datepicker ..etc.. we can build modules easily by doing so:
<form>
<div class="dropbox"><label for="someID">aaaaaa</label><input id="someID"/></div>
<div class="datepicker"></div>
<div class="othermodule"></div>
</form>
js:
$(".dropbox").dropbox(); // init dropbox you defined
$(".datepicker").datepicker(); // ...
$(".othermodule").othermodule(); // ...
$(".dropbox").dropbox("errorText", "error"); // invoke it smoothly
here is a simple demo: http://jsfiddle.net/m4A3D/
#Wouter Huysentruit's answer provides a list of good suggestion for me
<form>
<div class="dropbox">
<label for="someID">aaaaaa</label>
<input id="someID"/>
</div>
<div class="datepicker"></div>
<div class="othermodule"></div>
</form>
<button id="button1">Press me</button>
<script>
(function ($){
$.widget("my.dropbox", {
_create: function () {
var $input = this.element.find("input");
var sID = $input.attr("id");
var $select = $("<select>");
$select.attr("id", sID);
$input.replaceWith($select);
this.element.append("<div class='errors'></div>");
}, // end _create()
errorText: function (text) {
this.element.find(".errors").text(text);
} // end errorText()
});
}(jQuery));
$(".dropbox").dropbox();
$("#button1").click(function () {
$(".dropbox").dropbox("errorText", "this is error");
});
</script>

how to repeat same Javascript code over multiple html elements

Note: Changed code so that images and texts are links.
Basically, I have 3 pictures all with the same class, different ID. I have a javascript code which I want to apply to all three pictures, except, the code needs to be SLIGHTLY different depending on the picture. Here is the html:
<div class=column1of4>
<img src="images/actual.jpg" id="first">
<div id="firsttext" class="spanlink"><p>lots of text</p></div>
</div>
<div class=column1of4>
<img src="images/fake.jpg" id="second">
<div id="moretext" class="spanlink"><p>more text</p></div>
</div>
<div class=column1of4>
<img src="images/real.jpg" id="eighth">
<div id="evenmoretext" class="spanlink"><p>even more text</p></div>
</div>
Here is the Javascript for the id="firsttext":
$('#firstextt').hide();
$('#first, #firsttext').hover(function(){
//in
$('#firsttext').show();
},function(){
//out
$('#firsttext').hide();
});
So when a user hovers over #first, #firsttext will appear. Then, I want it so that when a user hovers over #second, #moretext should appear, etc.
I've done programming in Python, I created a sudo code and basically it is this.
text = [#firsttext, #moretext, #evenmoretext]
picture = [#first, #second, #eighth]
for number in range.len(text) //over here, basically find out how many elements are in text
$('text[number]').hide();
$('text[number], picture[number]').hover(function(){
//in
$('text[number]').show();
},function(){
//out
$('text[number]').hide();
});
The syntax is probably way off, but that's just the sudo code. Can anyone help me make the actual Javascript code for it?
try this
$(".column1of4").hover(function(){
$(".spanlink").hide();
$(this).find(".spanlink").show();
});
Why not
$('.spanlink').hide();
$('.column1of4').hover(
function() {
// in
$(this).children('.spanlink').show();
},
function() {
// out
$(this).children('.spanlink').hide();
}
);
It doesn't even need the ids.
You can do it :
$('.column1of4').click(function(){
$(this); // the current object
$(this).children('img'); // img in the current object
});
or a loop :
$('.column1of4').each(function(){
...
});
Dont use Id as $('#id') for multiple events, use a .class or an [attribute] do this.
If you're using jQuery, this is quite easy to accomplish:
$('.column1of4 .spanlink').hide();
$('.column1of4 img').mouseenter(function(e){
e.stopPropagation();
$(this).parent().find('.spanlink').show();
});
$('.column1of4 img').mouseleave(function(e){
e.stopPropagation();
$(this).parent().find('.spanlink').hide();
});
Depending on your markup structure, you could use DOM traversing functions like .filter(), .find(), .next() to get to your selected node.
$(".column1of4").hover(function(){
$(".spanlink").hide();
$(this).find(".spanlink, img").show();
});
So, the way you would do this, given your html would look like:
$('.column1of4').on('mouseenter mouseleave', 'img, .spanlink', function(ev) {
$(ev.delegateTarget).find('.spanlink').toggle(ev.type === 'mouseenter');
}).find('.spanlink').hide();
But building on what you have:
var text = ['#firsttext', '#moretext', '#evenmoretext'];
var picture = ['#first', '#second', '#third'];
This is a traditional loop using a closure (it's better to define the function outside of the loop, but I'm going to leave it there for this):
// You could also do var length = text.length and replace the "3"
for ( var i = 0; i < 3; ++i ) {
// create a closure so that i isn't incremented when the event happens.
(function(i) {
$(text[i]).hide();
$([text[i], picture[i]].join(',')).hover(function() {
$(text[i]).show();
}, function() {
$(text[i]).hide();
});
})(i);
}
And the following is using $.each to iterate over the group.
$.each(text, function(i) {
$(text[i]).hide();
$([text[i], picture[i]].join(', ')).hover(function() {
$(text[i]).show();
}, function() {
$(text[i]).hide();
});
});
Here's a fiddle with all three versions. Just uncomment the one you want to test and give it a go.
I moved the image inside the div and used this code, a working example:
$('.column1of4').each(function(){
$('div', $(this)).each(function(){
$(this).hover(
function(){
//in
$('img', $(this)).show();
},
function(){
//out
$('img', $(this)).hide();
});
});
});
The general idea is 1) use a selector that isn't an ID so I can iterate over several elements without worrying if future elements will be added later 2) locate the div to hide/show based on location relational to $(this) (will only work if you repeat this structure in your markup) 3) move the image tag inside the div (if you don't, then the hover gets a little spazzy because the positioned is changed when the image is shown, therefore affecting whether the cursor is inside the div or not.
EDIT
Updated fiddle for additional requirements (see comments).

manipulate a property of a child element

I have the following row element with a double click event atached to it.
<tr ondblclick="onLabelDoubleClicked(this)">
<td><label id="labelId" >My Label</label></td>
<td><input type="text" id="myInput" data-bind="kendoDropDownList: { data: source, value: myValue, enable: true }" /></td>
</tr>
On double click I need to set the enable property of kendoDropDownList in input element to toggle true/ false.
javascript:
onLabelDoubleClicked = function (event) {
}
I searched through the event properties but could not find anything useful to get the enable property and manipulate it. Any help with working example will be greatly appreciated. Thank You!
Instead of inlining the doubleclick event, it’s easier if you put the handler in the JS code and traverse/change the DOM from there.
I’m not sure about the Kendo stuff in the data-bind property, but it looks like a string to me so you’ll need to do string replaces unless you have a better way.
try this:
$('tr').dblclick(function() {
var $el = $(this).find(':text'),
data = $el.data('bind');
if (/true/.test(data)) {
data = data.replace(/true/,'false');
} else if (/false/.test(data)) {
data = data.replace(/false/,'true');
}
$el.prop('data-bind', data);
});
If you can use jQuery (and tag sets implies you're), why not just use jQuery (and Kendo) methods?
$('tr').dblclick(function() {
var $kd = $(this).find('input').data("kendoDropDownList");
$kd.enable( $kd.element.is(':disabled') );
});

how to get outerHTML with jquery in order to have it cross-browser

I found a response in a jquery forum and they made a function to do this but the result is not the same.
Here is an example that I created for an image button:
var buttonField = $('<input type="image" />');
buttonField.attr('id', 'butonFshi' + lastsel);
buttonField.val('Fshi');
buttonField.attr('src', 'images/square-icon.png');
if (disabled)
buttonField.attr("disabled", "disabled");
buttonField.val('Fshi');
if (onblur !== undefined)
buttonField.focusout(function () { onblur(); });
buttonField.mouseover(function () { ndryshoImazhin(1, lastsel.toString()); });
buttonField.mouseout(function () { ndryshoImazhin(0, lastsel.toString()); });
buttonField.click(function () { fshiClicked(lastsel.toString()); });
And I have this situation:
buttonField[0].outerHTML = `<INPUT id=butonFshi1 value=Fshi src="images/square-icon.png" type=image jQuery15205073038169030395="44">`
instead the outer function I found gives buttonField.outer() = <INPUT id=butonFshi1 value=Fshi src="images/square-icon.png" type=image>
The function is:
$.fn.outer = function(val){
if(val){
$(val).insertBefore(this);
$(this).remove();
}
else{ return $("<div>").append($(this).clone()).html(); }
}
so like this I loose the handlers that I inserted.
Is there anyway to get the outerHTML with jquery in order to have it cross-browser without loosing the handlers ?!
You don't need convert it to text first (which is what disconnects it from the handlers, only DOM nodes and other specific JavaScript objects can have events). Just insert the newly created/modified node directly, e.g.
$('#old-button').after(buttonField).remove();`
after returns the previous jQuery collection so the remove gets rid of the existing element, not the new one.
Try this one:
var html_text = `<INPUT id=butonFshi1 value=Fshi src="images/square-icon.png" type=image jQuery15205073038169030395="44">`
buttonField[0].html(html_text);
:)
Check out the jQuery plugin from https://github.com/darlesson/jquery-outerhtml. With this jQuery plugin you can get the outerHTML from the first matched element, replace a set of elements and manipulate the result in a callback function.
Consider the following HTML:
<span>My example</span>
Consider the following call:
var span = $("span").outerHTML();
The variable span is equal <span>My example</span>.
In the link above you can find more example in how to use .outerHTML() plug-in.
This should work fine:
var outer = buttonField.parent().html();

Categories

Resources