Working with getElementById( x ).onclick = someFunction - javascript

I thought for long how to define the question but i couldn't, i need to explain the code.
I want to make a simple organizer in JavaScript. You enter the task and click on the button "add to the list" and a script makes a checkbox with paragraph that contains the task's text. The second part is the disabling the checkbox, and striking through that tasks text when you click on it. I tried to do that by giving every checkbox i create a function (destroyIt() that gets element by id and than disables it, but it works only for the last checkbox added to the page. I am looking at this code for long time and i can't see what is wrong. Please help. Here is my code:
<html>
<head>
<style id="stil">
.over{
text-decoration:line-through;
}
</style>
<script type="text/javascript">
var numberOfTasks=1;
function insertNew(){
tekst = document.getElementById("zadatak").value;
if(tekst.length>0){
var idEl= "check"+numberOfTasks;
document.getElementById("ispis").innerHTML+="<input type='checkbox' id='check"+numberOfTasks+"'> "+"<span class='"+idEl+"'>"+tekst+"</span> <br/>";
document.getElementById(idEl).onclick= function(){ destroyIt(idEl); };
numberOfTasks++;
}
}
function destroyIt(idEl){
document.getElementById(idEl).disabled=true;
document.getElementById("stil").innerHTML+= "."+idEl+"{text-decoration:line-through;}";
alert(idEl+"{text-decoration:line-through;}");
}
</script>
</head>
<body>
Tasks for: <span id="date"> </span>
<script>
var date= new Date();
document.getElementById("date").innerHTML= ""+ date.getDay() +"." +date.getMonth() +"." +date.getFullYear();
</script>
<br/> <br/>
New task: <input type="text" id="zadatak"> <button onclick="insertNew()"> add to the list </button>
<button onclick="provera()">Provera</button>
<p id="ispis"> </p>
</body>

The problem is that when you do .innerHTML += "...", it destroys the existing nodes and their event handlers, and replaces them with new, clean nodes. For this and other reasons, you should almost never use += after .innerHTML.
A better way to insert new content from HTML markup is to use .insertAdjacentHTML() instead. The first argument describes the position relative to the element on which it was invoked, and the second argument is the new content.
So your code with .insertAdjacentHTML() would look like this:
function insertNew(){
tekst = document.getElementById("zadatak").value;
if(tekst.length>0){
var idEl= "check"+numberOfTasks;
document.getElementById("ispis")
.insertAdjacentHTML("beforeEnd", "<input type='checkbox' id='check"+numberOfTasks+"'> "+"<span class='"+idEl+"'>"+tekst+"</span> <br/>");
document.getElementById(idEl).onclick= function(){ destroyIt(idEl); };
numberOfTasks++;
}
}
Furthermore, you can modify the destroyIt function to operate on its this value, which will give you the input element that has the handler. You can then use its .id to get the class of the span, or you can just traverse to the next element.
Also, you shouldn't modify the style sheet to hide the element. Just add a class or a direct style property.
So in the above function, this:
document.getElementById(idEl).onclick= function(){ destroyIt(idEl); };
becomes this:
document.getElementById(idEl).onclick= destroyIt;
And then the destroyIt function becomes this:
function destroyIt(){
var span = this.nextElementSibling;
this.disabled=true;
span.style.textDecoration = "line-through";
}
The .nextElementSibling will need to be patched in IE8, but this is just for simple demonstration.

Related

Create a button to control the JavaScript create some elements. Then if any of these element changes, do something

I'd like to create a button using HTML. If user click the button, then use javascript to create some elements (like checkboxes). After these, if any of the elements changes, do something, like printing out some text.
Following is my code.
HTML:
<button id="try" type="button">TRY</button>
<div id="boxes"></div>
<p id="demo"></p>
Javascript:
doit = function(){
var checkboxes = "";
for(var i = 0;i<5;i++){
checkboxes += "<input type='checkbox' name='a'/>Option" + i+"<br>";
}
$("#boxes").html(checkboxes);
}
$('#try').click(function(){
doit();
})
$("input[name='a']").on("change",function(){
$("#demo").text("success!")
})
I really can't figure out where I am wrong. Demo:https://jsfiddle.net/slfan/cu7tn64o/12/.
Since you are dynamically adding new elements, you need to use a delegate event handler:
$(document).on("change", "input[name='a']", function() {
$("#demo").text("success!")
})
Updated JSFiddle: https://jsfiddle.net/cu7tn64o/14/

Variable Id Called in JS Function

I've spent the past couple hours googling and browsing W3Schools and couldn't find a way to do exactly what I wanted. I've found similar articles but they don't answer my question perfectly.
So what I'm trying to do is this, create a JS function that when called in HTML will take the information given to return the appropriate information. E.G, I want there to be two HTML buttons. If the user presses the first button, it calls the function "onclick='show(x, y)'" and x and y which stand for another paragraph and an image. If the user presses the second button, it calls the same function with different variables "onclick='show(x, z)'" which would display the same paragraph as the other button would but would display a different image.
Basically, is it possible for HTML elements to have IDs that can be variable in JS so I that I do not have to create an individual JS function for every single button?
My Javascript:
<script>
var Show = function(elID, elID2) {
var el1 = document.getElementByID(elID);
var el2 = document.getElementByID(elID2);
var both = (elID) + " " + (elID2);
document.getElementById(elID).innerHTML = both;
}
</script>
My HTML:
<p id="demo">
<button onclick="Show(77, demo)">Click to convert</button>
</p>
I am still learning the ins and outs of Javascript so any and all help would be appreciated.
yes, enclose the arguments in quotes
<button onclick="Show('77', 'demo')">Click to convert</button>
without quotes 77 will be passed correctly but demo will not be since it will look for a demo property in window scope.
You should get innerHTML before inserting. Also note that, you must pass id attributes wrapped in quotes(').
ID attributes should at least have one character and it should not start with NUMBER
function Show(elID, elID2) {
var el1 = document.getElementByID(elID).innerHTML;
var el2 = document.getElementByID(elID2).innerHTML;
var both = (elID) + " " + (elID2);
document.getElementById(elID).innerHTML = both;
}
<p id="demo">
<button onclick="Show('77', 'demo')">Click to convert</button>
</p>
You could lay aside the inline JavaScript and opt for a different way, separating your markup from your logic.
https://jsfiddle.net/tricon/p2esv818/
HTML:
<button id="button" data-parameter-one='{ "keyOne": "valueOne", "keyTwo": "valueTwo" }'>
Some button
</button>
JavaScript:
var button = document.getElementById("button");
button.addEventListener("click", function() {
var parameters = this.getAttribute("data-parameter-one");
parameters = JSON.parse(parameters);
console.log(parameters);
});

JS expand onClick multiple events

Please check this page first : Solarking - About Us
Check first 2 boxes which has a READ MORE button. On clicking them, they expand a paragraph.
Now I want it to be like when I click on it, it should expand the text and change the button value to "CLOSE" from "READ MORE". And on again clicking on "CLOSE", it should change value to "READ MORE".
I searched for long time to see how to fire multiple events on onClick, but I saw that some said to use a ; in them, some said make a new function and put 2 functions in it.
Now I tried to make a new function with 2 functions inside it (one to expand the paragraph, other to change value of button, but I failed. (I am new to JS).
Help please. Thank you in advance!
Code I have on the page :
button code:
<p style="text-align: right;"><input id="button12" style="background-color: #eca200; color: #ffffff;" onclick="return toggleMe('para1')" type="button" value="Read more" /></p>
Script :
<script type="text/javascript">
function toggleMe(a){
var e=document.getElementById(a);
if(!e)return true;
if(e.style.display=="none"){
e.style.display="block"
}
else{
e.style.display="none"
}
return true;
}
</script>
I think the easiest way to do this would be to set a boolean variable. In other words, let's say that it starts off with the dclaration at the beginning of the page.
var hasbeenclicked = false;
Then, after the first click
hasbeenclicked = true;
After a second click
hasbeenclicked = false;
When the function is called, it checks the variable and operates accordingly. The following is not real JS....
if hasbeenclicked = true {
do some stuff;
}
else {
do some other stuff;
}
That is a simple way to accomplish what you are trying to do.
Additional info:
Use two DIV tags with separate ID's. One for the paragraph and one for the "label". Use getelementbyID to alter each one appropriately.
I noticed you are using jQuery.
You could use a toggle method.
Alter the html link. Add a class of expander and use the data attribute to identify the paragraph id
<p style="text-align: right;">
<input id="button12" data-toggle="para1" class="expander" style="background-color: #eca200; color: #ffffff;" type="button" value="Read more" />
</p>
The JS
$(".expander").click(function() {
var self = $(this);
$("#" + self.data('toggle')).slideToggle(500, function () {
if ($("#" + self.data('toggle')).is(':visible')) { // paragraph is open
self.val("Close");
} else { // paragraph is closed
self.val("Read More");
}
});
});

How to Reduce Size of This jQuery Script and Make it More Flexible?

I just created script that shows/hides (toggles) block of HTML. There are four buttons that each can toggle its HTML block. When any HTML block is opened, but user has been clicked on other button than that HTML block's associated button... it hides that HTML block and shows new one.
Here is what I have at the moment:
$('.btn_add_event').click( function() {
$('.block_link, .block_photos, .block_videos').hide();
$('.block_event').toggle();
});
$('.btn_add_link').click( function() {
$('.block_event, .block_photos, .block_videos').hide();
$('.block_link').toggle();
});
$('.btn_add_photos').click( function() {
$('.block_event, .block_link, .block_videos').hide();
$('.block_photos').toggle();
});
$('.btn_add_videos').click( function() {
$('.block_event, .block_link, .block_photos').hide();
$('.block_videos').toggle();
});
Any ideas how to reduce code size? Also, this script isn't very flexible. Imagine to add two new buttons and blocks.
like Sam said, I would use a class that all the blocks share, so you never have to alter that code. Secondly, you can try 'traversing' to the closest block, therefore avoiding it's name. That approach is better than hard coding each specific block, but if the html dom tree changes you will need to refactor. Last, but best, you can pass in the class name desired block as a variable to the function. Below is something you can copy paste that is close to what you started with.
$('.myAddButtonClass').click( function() {
$('.mySharedBlockClass').filter(':visible').hide();
//find a good way to 'traverse' to your desired block, or name it specifically for now.
//$(this).closest(".mySharedBlockClass").show() complete guess
$('.specificBlockClass').show();
});
I kept reading this "When any HTML block is opened, but user has been clicked on other button than that HTML block's associated button" thinking that my eyes were failing me when Its just bad English.
If you want to make it more dynamic, what you can do is add a common class keyword. Then
when the click event is raise. You can have it loop though all the classes that have the
keyword and have it hide them all (except the current one that was clicked) and then show the current one by using the 'this' keyword.
you can refer below link,
http://chandreshmaheshwari.wordpress.com/2011/05/24/show-hide-div-content-using-jquery/
call function showSlidingDiv() onclick event and pass your button class dynamically.
This may be useful.
Thanks.
try this
$('input[type=button]').click( function() {
$('div[class^=block]').hide(); // I resumed html block is div
$(this).toggle();
});
Unfortunatly I couldn't test it, but if I can remember right following should work:
function toogleFunc(clickObject, toogleTarget, hideTarget)
{
$(clickObject).click(function()
{
$(hideTarget).hide();
$(toogleTarget).toggle();
});
}
And the call:
toogleFunc(
".btn_add_videos",
".block_videos",
".block_event, .block_link, .block_photos"
);
and so far
Assuming the buttons will only have one class each, something like this ought to work.
var classNames = [ 'btn_add_event', 'block_link', 'block_photos', 'block_videos' ];
var all = '.' + classNames.join(', .'); // generate a jquery format string for selection
$(all).click( function() {
var j = classNames.length;
while(j--){
if( this.className === classNames[j] ){
var others = classNames.splice(j, 1); // should leave all classes but the one on this button
$('.' + others.join(', .')).hide();
$('.' + classNames[j]).toggle();
}
}
}
All the buttons have the same handler. When the handler fires, it checks the sender for one of the classes in the list. If a class is found, it generates a jquery selection string from the remaining classes and hides them, and toggles the one found. You may have to do some checking to make sure the strings are generating correctly.
It depends by how your HTML is structured.
Supposing you've something like this
<div class="area">
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
</div>
...
<div class="sender">
<a class="one"></a>
<a class="two"></a>
<a class="three"></a>
</div>
You have a class shared by the sender and the target.
Your js would be like this:
$('.sender > a').click(function() {
var target = $(this).attr('class');
$('.area > .' + target).show().siblings().hide();
});
You show your real target and hide its siblings, which aren't needed.
If you put the class postfixes in an array, you can easily make this code more dynamic. This code assumed that it doesn't matter in which order toggle or hide are called. If it does matter, you can just remember the right classname inside the (inner) loop, and toggle that class after the loop.
The advantage to this approach is that you can extend the array with an exta class without needing to modifying the rest of the code.
var classes = new Array('videos', 'event', 'link', 'photos');
for (var i = 0; i < classes.length; ++i)
{
$('.btn_add_' + classes[i]).click(
function()
{
for (var j = 0; j < classes.length; ++j)
{
if (this.hasClass('btn_add_' + classes[j]))
{
$('.block_' + classes[j]).toggle();
}
else
{
$('.block_' + classes[j]).hide();
}
}
});
}
You could make this code more elegant by not assigning those elements classes like btn_add_event, but give them two classes: btn_add and event, or even resort to giving them id's. My solution is based on your description of your current html.
Here is what I think is a nice flexible and performant function. It assumes you can contain your links and html blocks in a parent, but otherwise it uses closures to precalculate the elements involved, so a click is super-fast.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" ></script>
<script type="text/javascript">
// Enables show/hide functionality on click.
// The elements within 'container' matching the selector 'blocks' are hidden
// When elements within 'container' matching the selector 'clicker' are clicked
// their attribute with the name 'clickerAttr' is appended to the selector
// 'subject' to identify a target, usually one of the 'blocks'. All blocks
// except the target are hidden. The target is shown.
//
// Change clickerAttr from 'linkTarget' to 'id' if you want XHTML compliance
//
// container: grouping of related elements for which to enable this functionality
// clicker: selector to element type that when clicked triggers the show/hide functionality
// clickerAttr: name of the DOM attribute that will be used to adapt the 'subject' selector
// blocks: selector to the html blocks that will be shown or hidden when the clicker is clicked
// subject: root of the selector to be used to identify the one html block to be shown
//
function initToggle(container,clicker,clickerAttr,blocks,subject) {
$(container).each(
function(idx,instance) {
var containerElement = $(instance);
var containedBlocks = containerElement.find(blocks);
containerElement.find(clicker).each(function(idxC, instanceClicker) {
var tgtE = containerElement.find(subject+instanceClicker.getAttribute(clickerAttr));
var clickerBlocks = containedBlocks.not(tgtE);
$(instanceClicker).click(function(event) {
clickerBlocks.hide();
tgtE.toggle();
});
});
// initially cleared
containedBlocks.hide();
}
);
}
$(function() {
initToggle('.toggle','a.link','linkTarget','div.block','div.');
});
</script>
</head>
<body>
Example HTML block toggle:
<div class="toggle">
a <br />
b <br />
c <br />
<div class="A block"> A </div>
<div class="B block"> B </div>
<div class="C block"> C </div>
</div> <!-- toggle -->
This next one is not enabled, to show scoping.
<div class="toggle2">
a <br />
<div class="A block">A</div>
</div> <!-- toggle2 -->
This next one is enabled, to show use in multiple positions on a page, such as in a portlet library.
<div class="toggle">
a <br />
<div class="A block">A</div>
</div> <!-- toggle (2) -->
</body>
</html>

how to get tinyMCE editable for a cloned textarea by cloneNode(true) function

When I try to clone a textarea by using cloneNote(true), the cloned textarea is not editable. Does anyone know how to resolve the problem? The sample codes show as following:
<html>
<head>
<script type="text/javascript" src="/javascripts/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({
theme : "advanced",
mode : "textareas",
});
</script>
<script type="text/javascript">
testclonenode = {
addAbove : function (element) {
var rowEl = element.parentNode.parentNode.parentNode;
var rowElClone = rowEl.cloneNode(true);
rowEl.parentNode.insertBefore(rowElClone, rowEl);
return false;
}
};
</script>
</head>
<body>
<table>
<tr><td>
<textarea name="content" style="width:100%">this is a test </textarea>
<p> <button onclick='return testclonenode.addAbove.call(testclonenode, this);'> Add above </button>
</td></tr>
</table>
</body></html>
It does not work that way. Also, it is impossible to move a tinymce editor using dom manipulation.
The tinymce wiki states the following:
mceAddControl
Converts the specified textarea or div
into an editor instance having the
specified ID.
Example:
tinyMCE.execCommand('mceAddControl',false,'mydiv');
So when you clone a textarea there is another problem: You will have the same id twice which will result in errors accessing the right tinymce instance.
I got this to work by using an ID which is incremented each time my clone function is triggered, so
var insertslideID = 0;
function slideclone() {
$('<div class="slides"><textarea name="newslide['+insertslideID+'][slide_desc]" id="mydiv'+insertslideID+'"></textarea></div>').insertAfter('div.slides:last');
tinyMCE.execCommand('mceAddControl',false,'mydiv'+insertslideID);
insertslideID++;
}
$('input[name=addaslidebtn]').click(slideclone);
Seems to work.
A wee bit tidier, I just use a number for my id - copy1 is the name of my button - I add the new element to the end of my container.
var count = 0;
$("#copy1").click(function(){
var newId = count;
$( "#first" ).clone().appendTo( "#container" ).prop({ id: newId, });
tinyMCE.execCommand('mceAddControl',false,newId);
count++;
});
I ran into a similar problem, except my element IDs (not just textareas) could be anything, and the same ID was always appearing twice. What I did is supposed to be horribly inefficient but there was no noticeable performance loss with dozens of elements on the page.
Basically I removed the TinyMCE ID first (uses jQuery):
$(new_element).find('.mce-content-body').each(function () {
$(this).removeAttr('id');
});
Then I reinitialized TinyMCE for all relevant elements.

Categories