Can't bind event to element, created by script - javascript

I'm learning a pure JavaScript. Currently I'm exploring DOM objects, like WINDOW, DOCUMENT, ELEMENT and so on ...
I'm creating text fields on a fly and want to bind function to each element's event (onfocus or onblur for example), and pass self element as argument (like 'this').
The following script creates text field and binds it to a specific function.
var txt= document.createElement("input");
txt.type="text";
txt.value='0';
txt.size=12;
txt.style.textAlign="right";
txt.id="txt_"+self.count;
txt.addEventListener('focus', txt_focus(txt));
txt.addEventListener('blur', txt_blur(txt));
And below is the functions:
function txt_focus(txt){
txt.value=txt.id;
txt.style.backgroundColor='yellow';
}
function txt_blur(txt){
txt.style.backgroundColor='white';
}
This function recognizes given argument as element and sets its ID to value attribute, but it not affects to background color.
What have I missed?
Here is the entire HTML code:
<html>
<head>
<script type="text/javascript">
self.count =0;
function txt_focus(txt){
txt.value=txt.id;
txt.style.backgroundColor='yellow';
}
function txt_blur(txt){
txt.style.backgroundColor='white';
}
function removeGroup(){
if (self.count<1) {return;}
var parent=document.getElementById("myDiv");
var fs_x =document.getElementById('fs_'+self.count);
parent.removeChild(fs_x);
self.count--;
}
function addGroup(){
if (self.count>11) {return;}
self.count++;
var parent=document.getElementById("myDiv");
var fs=document.createElement("fieldSet");
fs.style.borderRadius="7px";
fs.style.height="45px";
fs.id='fs_'+self.count;
var l=document.createElement("legend");
l.innerHTML="interval_"+self.count;
l.style.color="darkgreen";
l.style.fontStyle="italic";
fs.appendChild(l);
var d1= document.createElement("input");
d1.type="date";
d1.value='2014-05-01';
d1.id='d1_'+self.count;
fs.appendChild(d1);
var d2= document.createElement("input");
d2.type="date";
d2.value='2014-05-22';
d2.id='d2_'+self.count;
fs.appendChild(d2);
var txt= document.createElement("input");
txt.type="text";
txt.value='0';
txt.size=12;
txt.style.textAlign="right";
txt.id="txt_"+self.count;
txt.addEventListener('focus', txt_focus(txt));
txt.addEventListener('blur', txt_blur(txt));
fs.appendChild(txt);
parent.appendChild(fs);
fs.scrollIntoView();
}
</script>
</head>
<body>
<input type="hidden" id="hd1" value="0"> </input>
<button onclick="addGroup();"> Add a group</button>
<button onclick="removeGroup();"> Remove a group</button>
<div id="myDiv" style="padding:7px;position:relative;margin-top:15px;width:500px;height:500px;background-color:#ccbbcc;overflow-y:auto;border:1px red solid;border-radius:15px;">
</div>
</body>
</html>
Solution is desired in pure JavaScript, but JQuery solution is also interesting.
My second question is:
I've some background of basic JavaScript (like Math, strings, functions, arrays, classes and so on), and there I want your advice: Is there any necessity to dig deep into JavaScript details instead of jump to a JQuery?

The issue here is the difference between referencing a function and calling it. Whenever you add the parenthesis you call the function and return the result, and the default result is undefined.
In an event handler you want to reference the function only
txt.addEventListener('focus', txt_focus);
If you have to pass arguments, you'd use an anonymous function
txt.addEventListener('focus', function() {
txt_focus(txt);
});
but here that doesn't make sense, as you're passing the element, which you could access with this inside the function instead
txt.addEventListener('focus', txt_focus);
function txt_focus() {
var txt = this; // the element
}

Related

Variable doesn't update after having event listener

I cannot update the value for userPickColor for some reason, it is always undefined. But I try to console.log inside the functions and my values are actually changing. But for some reasons, once I call it outside the function, it doesn't update at all.
I'm still new to Javascript so Please Help me
Here is my code:
var white = document.getElementById("white");
var black = document.getElementById("black");
var userPickColor;
white.addEventListener("click", whiteshirt);
black.addEventListener("click", blackshirt);
function whiteshirt(){
userPickColor= "white";
}
function blackshirt(){
userPickColor= "black";
}
ShirtDescrp.innerHTML = userPickColor;
As others have said, you need to place the line that updates the .innerHTML inside of the callback functions so that after the variable has been updated, you can update the page with the most current variable value as well.
But, taking this one step further... There is a common coding methodology called DRY (Don't Repeat Yourself) and you've got two callback functions that largely do the same thing. The only difference is the actual text that gets set. Those two functions run when one of two elements on your page get clicked and those two elements have the text you want to use as their ids. We could easily combine the two callbacks into just one like this:
var ShirtDescrp = document.getElementById("des");
// There's nothing wrong with variables if they help you read the code
// more easily, but if you won't be using the value they store more than
// once, they don't really add much.
document.getElementById("white").addEventListener("click", changeColor);
document.getElementById("black").addEventListener("click", changeColor);
function changeColor() {
// No variable needed. Just set the text to the id of the element that got clicked
// "this" here refers to the object that initiated the call for the current function
// which will be one of the two buttons.
ShirtDescrp.innerHTML = this.id;
}
<button id="white">white</button>
<button id="black">black</button>
<p id="des"></p>
you have to put ShirtDescrp.innerHTML = userPickColor; inside your event listener as well since you change the variable but you didn't tell the dom to update the content
You should update the DOM same as the variable:
var white = document.getElementById("white");
var black = document.getElementById("black");
var ShirtDescrp = document.getElementById("des");
var userPickColor = null;
white.addEventListener("click", whiteshirt);
black.addEventListener("click", blackshirt);
function whiteshirt() {
userPickColor = "white";
ShirtDescrp.innerHTML = userPickColor;
}
function blackshirt() {
userPickColor = "black";
ShirtDescrp.innerHTML = userPickColor;
}
<button id="white">white</button>
<button id="black">black</button>
<p id="des"></p>
You have already got your answer... Change doesn't affect as update is not happening inside event listener. This is just a recommendation how I would do it (especially if i had more color options):
<p id="color-name">none</p>
<div class="color-buttons">
<button id="white">White</button>
<button id="black">Black</button>
<button id="orange">Orange</button>
<button id="blue">Blue</button>
<button id="green">Green</button>
<button id="red">Red</button>
</div>
JavaScript like:
var buttons = document.querySelectorAll(".color-buttons button");
var color_name = document.getElementById("color-name");
buttons.forEach(function(btn){
btn.addEventListener("click", function(){
color_name.style.background=this.id;
color_name.innerHTML=this.id;
});
});
Here is the fiddle to play around.
I would also probably generate those buttons dynamically as well. And also wouldn't use id to store color but i would use something else like data-color='red' for example.

Variable value not accumulating?

Hey I'm very new to JS but cannot figure out why the 3 variables at the top aren't accumulating?
var xe = 0;
var reckon = 0;
var books = 0;
document.getElementById('#go').addEventListener('click', function(){
questionOne();
});
document.getElementById('#macos').addEventListener('click',function(){
addXe();
questionThree();
});
document.getElementById('#windows').addEventListener('click',function(){
questionThree();
});
document.getElementById('#linux').addEventListener('click', function(){
questionThree();
});
document.getElementById('#large').addEventListener('click', function(){
questionFour();
addXe();
});
function addXe(){
xe++;
};
function addReckon(){
reckon++;
};
function addBooks(){
books++;
};
The rest of the code is simply a series of functions that toggles divs display on and off.
If Ive missed and important info out let me know,
Thanks!
EDIT:
github.com/daffron/accountingsoftware
I thought it would be easier to attach the whole site, the problem is each time the addXero function is executed , it doesn't accumulate the value of var xero, I have it printing to console in the other functions. Thanks –
Your parameters for document.getElementById() are wrong.
If your HTML code for a button is like this:
<input type="button" id="go" />
<!-- OR like this: -->
<button id="go" ></button>
Then your javascript code must access the button using the method getElementById() as:
document.getElementById("go");
So, one of your functions will be like:
document.getElementById('go').addEventListener('click', function(){
questionOne();
});
BUT, if you've used '#go' because you were referring to a CSS Selector then you've to use querySelector method instead of getElementByIdas:
document.querySelector("#go");
So, a function call as per your code will be:
document.querySelector('#go').addEventListener('click', function(){
questionOne();
});
you should have html label example
<label id="xeLbl">test</label>
and after changing value you should apply it to html label.
function addXe(){
xe++;
document.getElementById('xeLbl').innerHTML = xe;
};

detect element where the function was called from

I need to know where my jQ function was called from...
In head:
function call_pl2(){
$(this).text('some text');
}
in Body:
<p> <script> call_pl2(); </script> </p>
<!-- OR -->
<div> <script> call_pl2(); </script> </div>
I got your point, I'm afraid you cannot get from the function the element that your js function is there, but each time that your function is called you can use another function and search your html content to see where this function is inside. I assume that this function is called ones from the html code when this is loaded.
Instead of trying to determine which element contains the the script tag (and, by extension, a particular call to call_pl2()) you could explicitly pass the containing element to call_pl2() as a parameter:
$(function() {
var call_p12 = function(element) {
if ($(element).is('p')) {
$(element).text('here is some text added to a paragraph');
}
if ($(element).is('div')) {
$(element).text('here is some text added to a div');
}
}
$('div, p').each(function() {
call_p12($(this));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<p></p>
<div></div>
It would be relatively easy to modify the call_p12() function to swap in a more specific selector in the jQuery is(). For example is('.someclass') to check for a class value instead of a tag name.

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 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