I'm generating some HTML at runtime and I'm wondering how to make a plugin work on the newly created HTML. I've got something that looks llike this:
<input type="text" class="SomeClass">
<div id="Test"></div>
<script>
function Start() {
setTimeout(function () {
$('#Test').html('<input type="text" class="SomeClass">');
}, 1000);
}
$(".SomeClass").SomePlugin();
$(Start);
</script>
The input element has all the functionalities of the plugin but when I add the HTML inside the Test div the input element inside there doesn't work as expected. How can I use the plugin on dynamically generated HTML?
For plugin to work with new created elements, you need to init the plugin on those elements for it to work. There are several ways to do this, such as calling it again when new elements are added.
If you just want to avoid changing your code and adding that, you could override jquery html to check if you are adding an element with SomeClass and call the plugin for it automatically:
(function($)
{
var oldhtml = $.fn.html; //store old function
$.fn.html = function() //override html function
{
var ret = oldhtml.apply(this, arguments); // apply jquery html
if(arguments.length){
if(ret.find(".SomeClass").length){
ret.find(".SomeClass").SomePlugin(); // call plugin if the html included an element with .SomeClass
}
}
return ret;
};
})(jQuery);
$.fn.SomePlugin = function() {
$("body").append("plugin activated <br/>");
}
function Start() {
setTimeout(function() {
$('#Test').html('<input type="text" class="SomeClass">');
$('#Test').html()
}, 1000);
}
$(".SomeClass").SomePlugin();
$(Start);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" class="SomeClass">
<div id="Test"></div>
I opted for a solution that used jQuery promises. Here is the Fiddle
The HTML (basic copy of yours):
<input type="text" class="SomeClass">
<div id="Test"></div>
The Javascript:
$.fn.SomePlugin = function(){
$(this).val("plugin activated");
}
function Start() {
alert('hi from start');
$('#Test').html('<input type="text" class="SomeClass">');
return $.when();
}
$(document).ready(function(){
Start().then(function () {
alert('hi from done');
$(".SomeClass").SomePlugin();
});
});
I had some issue with the $(Start) so i opted for the document.ready approach. The only real difference is that Start returns $.when (SO Post Here) and I chain a 'then' after the call to start. This allows the page to setup and then you can run any plugins that you want and ensure that the required elements are in the DOM before the plugin attempts to manipulate them.
Related
I learned that you can update a content inside div by using jQuery. I want to improve this code as the content is being change after it loads. I want it to be permanent regardless if it's loading or not.
Here's my code.
function changeContent () {
var myelement = document.getElementById("topbarlogin");
myelement.innerHTML= "HELLO";
}
window.onload = changeContent ;
This is my html code
<div class="signuplink" id="topbarlogin">Login</div>
Either call your function at the end of your body tag without window.load in script tag...
It will execute function() faster than the window.load
Stack Snippet
<body>
<div class="signuplink" id="topbarlogin">Login</div>
<script>
function changeContent() {
var myelement = document.getElementById("topbarlogin");
myelement.innerHTML = "HELLO";
}
changeContent();
</script>
</body>
...Or you can use DOMContentLoaded EventListener...it is equivalent to the $(document).ready() jQuery
function changeContent() {
var myelement = document.getElementById("topbarlogin");
myelement.innerHTML = "HELLO";
}
document.addEventListener("DOMContentLoaded", function(event) {
changeContent();
});
<div class="signuplink" id="topbarlogin">Login</div>
On DOM Ready use .html() to set HTML of div.
// This is you DOM Ready
$(function(){
// Set HTML using jQuery
$("#topbarlogin").html("HELLO");
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="signuplink" id="topbarlogin">Login</div>
Please try this
$("#topbarlogin").html("Hello");
I have this working example of jstree properly initiated allowing to browse through tree structure and trigger action when user clicks the node: https://jsfiddle.net/8v4jc14s/.
When I try to load the tree dynamically it's not working:
<div id="container">
<button onclick="load()">Load tree</button>
</div>
<script>
$(function () {
$('#tree_div')
.jstree()
.on('changed.jstree', function (e, data) {
alert(data.selected);
});
});
function load() {
document.getElementById("container").innerHTML = "<div id=\"tree_div\"><ul><li id=\"Root\">Root<ul><li id=\"Sub\">Sub</li></ul></li></ul></div>";
}
</script>
Is there a way to "initiate" the tree after dynamic load?
You can copy but you cannot bind events to copied element since you have initialized only one instance of jstree.
If you want another jstree, you need to make another instance.
You can check this:
$(function () {
$('#tree_div')
.jstree()
.on('changed.jstree', function (e, data) {
alert(data.selected);
});
attach();
second();
});
//just copies UI
function attach(){
var $elem = $("#tree_div").clone(true, true);
$("#myTest").append($elem);
}
//for another instance
function second(){
$('#yourTest')
.jstree()
.on('changed.jstree', function (e, data) {
alert(data.selected);
});
}
https://jsfiddle.net/8v4jc14s/3/
During further research I have found this question: How do you execute a dynamically loaded JavaScript block?
I have used answer from Roman coming up with below code that looks to be working well.
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
<div id="container">
<button onclick="load()">Load tree</button>
</div>
<script>
function load() {
// Clear container DIV to avoid adding tree div multiple times on multiple clicks
document.getElementById('container').innerHTML = "<button onclick=\"load()\">Load tree</button>";
// Creating new DIV element
var newdiv = document.createElement('div');
// Creating a jstree structure under newly created DIV
newdiv.innerHTML = "<div id=\"tree_div\"><ul><li id=\"Root\">Root<ul><li id=\"Sub\">Sub</li></ul></li></ul></div>";
// Creating new SCRIPT element
var script = document.createElement('script');
// Creating SCRIPT element content
script.innerHTML = "$(function () {$('#tree_div').jstree().on('changed.jstree', function (e, data) {alert(data.selected);});});";
// Adding SCRIPT element to newly created DIV
newdiv.appendChild(script);
// Finally updating "container" DIV
document.getElementById('container').appendChild(newdiv);
}
</script>
Hope this helps others like me lost in mysteries of JS :)
i want to create a flexible jquery plugin for handling forms, here's my markup + code:
<div id="myform" validate="1">form</div>
<script>
(function ($) {
$.fn.myForm = function()
{
var me = this;
if(me.attr("validate"))
{
me.validate();
}
};
})(jQuery);
// code from external file eg. myform_validate.js
$.fn.myplugin.validate = function () {
// form validation here
alert("validate");
};
$(document).ready(function(){
$('#myform').myForm();
});
</script>
what i want to achieve is somekind of plugin-in-plugin structure which means myForm is the base plugin for each project and if required i would add extra functionality/methods like form validation or an image uploader to the plugin (by loading additional external scripts).
this should be dont without instantiation, directly inside the plugin.
as you might expect, the above code doesn't work .. :/
any ideas if this is possible?
thanks
There are probably numerous ways to achieve expected results. Here, checks if validate method from "external file" is defined, if yes, sets validate as property of myForm ; utilizes Function.prototype.call to set this within validate
(function($) {
function myForm() {
me = this;
if (me.attr("validate")) {
if (myForm.validate) {
myForm.validate.call(me)
.text(me.text() + " validated")
.css("color", "green");
}
};
return me
};
try {
if (validate && typeof validate === "function") {
myForm.validate = validate
}
// catch `ReferenceError` if `validate` is not defined
} catch (e) {
alert(e.message)
}
$.fn.myForm = myForm;
})(jQuery);
// code from external file eg. myform_validate.js
$(document).ready(function() {
$("#myform").myForm();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<script>
// external file
function validates() {
// form validation here
console.log(this)
alert("validate");
// `this` : `#myform`
return this
};
</script>
<div id="myform" validate="1">form</div>
I am looking to hide several divs one by one or with a time interval of 5 seconds, i tried below doesn't seem to work though
<div id="container">
<div id="data1">123</div>
<div id="data2">456</div>
<div id="data3">789</div>
<div id="data4">012</div>
</div>
<script>
$('document').ready(function(){
window.setTimeout('mytimer()',5000);
});
$('document').ready(function(){
window.setTimeout('mytimer2()',10000);
});
$('document').ready(function(){
window.setTimeout('mytimer3()',15000);
});
$('document').ready(function(){
window.setTimeout('mytimer4()',20000);
});
function mytimer(){ $('#data1').hide(); }
function mytimer2(){ $('#data2').hide(); }
function mytimer3(){ $('#data3').hide(); }
function mytimer4(){ $('#data4').hide(); }
</script>
I would use single timeout function as your are hiding at regular intervals. There is one mistake in your code you need to pass the reference of function to setTimeout instead of passing the function call as a string.
Live Demo
window.setTimeout(mytimer,1000);
index = 1;
function mytimer()
{
$('#data' + (index++)).hide();
if(index <= 4) window.setTimeout(mytimer,1000);
}
You need to use $(document) instead of $('document')
$('document') will look for HTML Element with document tag, which doesn't exist.
Learn to use developer tools, Here's a good read: How to open the JavaScript console in different browsers?
Code
$(document).ready(function(){
window.setTimeout(mytimer,5000); //You can simply pass the function reference
window.setTimeout(mytimer2,10000);
window.setTimeout(mytimer3,15000);
window.setTimeout(mytimer4,20000);
});
Try it this way:
$(document).ready(function(){
window.setTimeout(mytimer, 5000);
window.setTimeout(mytimer2, 10000);
window.setTimeout(mytimer3, 15000);
window.setTimeout(mytimer4, 20000);
});
function mytimer(){
$('#data1').hide();
}
function mytimer2(){
$('#data2').hide();
}
function mytimer3(){
$('#data3').hide();
}
function mytimer4(){
$('#data4').hide();
}
Well you can use setInterval function too for this and once all the elements have been hidden you can clearInterval like one below:
DEMO HERE
function mytimer(elem){
console.log('came here');
$(elem).hide();
}
$(document).ready(function(){
var i=0;
var interval=null;
interval = window.setInterval(function(){
i++;
if(i<=$('#container').children().length)
mytimer("#data"+i);
else
{
clearInterval(interval);
return;
}
},5000);
});
Try this change and so on for the rest:
window.setTimeout(mytimer, 5000);// removed quotes and `()`
Another solution using jQuery fadeOut():
$(function() {
for (var i = 1; 4 >= i; i++)
$('#data' + i).fadeOut(5000 * i);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="container">
<div id="data1">123</div>
<div id="data2">456</div>
<div id="data3">789</div>
<div id="data4">012</div>
</div>
Use .delay() in jquery . No Settimeout function needed.
$('#data1').delay(5000).hide('fast');
$('#data2').delay(10000).hide('fast');
$('#data3').delay(15000).hide('fast');
$('#data4').delay(20000).hide('fast');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="data1">123</div>
<div id="data2">456</div>
<div id="data3">789</div>
<div id="data4">012</div>
</div>
There are multiple errors in your code.
You have used $('document').ready(function(){}), which is incorrect. document is a keyword, it shouldn't be in quotes.
You don't have to use multiple instance of calling $(document).ready(). You can call all your statements from a single function. You can also use $(function(){}).
While calling the function name inside the timeout function, you shouldn't put them under quotes. They act like keywords after you have defined them in your code. The function call inside the Timeout function shouldn't be followed by (). So it should be window.setTimeout(mytimer,5000);
Please refer the fiddle : http://jsfiddle.net/65gs8s9y/
I have modified your code which works fine now:
$(document).ready(function(){
window.setTimeout(mytimer,5000);
window.setTimeout(mytimer2,10000);
window.setTimeout(mytimer3,15000);
window.setTimeout(mytimer4,20000);
});
function mytimer(){
$('#data1').hide();
}
function mytimer2(){
$('#data2').hide();
}
function mytimer3(){
$('#data3').hide();
}
function mytimer4(){
$('#data4').hide();
}
I have an external JavaScript library to generate some formatted content. Let's call it ExternalLibrary.GenerateGutterDivs()
This code generates a table structure with some divs, something like:
<table>
<tr>
<td class="gutter">
<div>1</div>
<div>2</div>
<div>3</div>
...
</td>
<tr>
</table>
Once the table has been generate, I want to manipulate the generated DOM objects as follows:
<script type="text/javascript">
ExternalLibrary.generateGutterDivs();
alert("shomething"); //if I comment this I don't see the second alert
$("td.gutter > div").each(function(index, val)
{
alert("gutterfound");
});
</script>
The problem is that if I remove the first alert("something"), I don't see the second alert. This make think about the DOM maybe is not inmediatly refreshed. Do you know why I'm experiencing this situation?
Thanks in advanced.
This is a common issue. You should be returning a reference to the divs from MyCode.generateGutterDivs(), for example:
MyCode.generateGutterDivs = function () {
var safeReference = $("<div>1</div><div>2</div><div>3</div>")
.appendTo("td.gutter");
return safeReference;
};
Then:
<script type="text/javascript">
var divs = MyCode.generateGutterDivs();
divs.each(function(index, val)
{
alert("gutterfound"); // Should see 3 of these now
});
</script>
Edit: Since modifying the library is not an option for the poster, I think a setTimeout for 0 milliseconds will do the trick, yielding to the browser to finish updating the DOM:
<script type="text/javascript">
MyCode.generateGutterDivs();
setTimeout(function () {
divs.each(function(index, val)
{
alert("gutterfound"); // Should see 3 of these now
});
}, 0);
</script>
MyCode.GenerateGutterDivs() has not finished generating the DOM elements before the jQuery snippet is fired. You'll need to modify MyCode.GenerateGutterDivs() to accept a callback function, something akin to this:
MyCode.GenerateGutterDivs(function() {
$("td.gutter > div").each(function(index, val) {
alert("gutterfound");
});
});
//inside MyCode
GenerateGutterDivs = function(callback) {
// Generate formatted content.
callback();
};
Here's a proof of concept: http://jsfiddle.net/gnbNt/2/