Dynamic load of whole jstree - javascript

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

Related

Updating page content except one div using Ajax

I am trying to make a website that loads all pages using AJAX. Here's a simple piece of JS that does that:
$.ajax({
url: url,
type: 'GET',
success: function(html) {
document.open();
document.write(html);
document.close();
}
});
This obviously works and updates my current page content.
The problem is I want to keep one div unchanged (let's call it .player-wrapper). This div is actually an <audio> wrapper which I want to keep playing (and this is the reason I AJAXified the entire website). Is this possible?
Every time you render a page, you can initialize plugins/libraries like this:
const App = function() {
return {
init: function() {
// Do all your JS stuff here
console.log('App initialized.');
},
render: function(url) {
$.get(url, data => {
$('main').html(data);
}, 'html').done(() => {
this.init();
});
}
};
}();
$(function() {
App.init();
$(document).on('click', '[data-page="ajax"]', function (e) {
e.preventDefault();
const url = $(this).attr('href');
App.render(url);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<audio class="player-wrapper" src="https://www.free-stock-music.com/music/alexander-nakarada-wintersong.mp3" controls autoplay></audio>
<main>
<h1>Initial page.</h1>
</main>
<nav>
Go to dummy page
</nav>
If you want to keep the audio tag with the player-wrapper class let's take this html as our base:
<body>
<audio class="player-wrapper"></audio>
<div class="page-content"></div>
</body>
Then with the following code you can place the html you received from the ajax request:
document.querySelector('.page-content').innerHTML = html;
Just don't write the html to the document, but place it in an already existing element like the div with the page-content class in this example.
And when you need to execute script tags in the html you can use jQuery's append method (since you are already using jQuery)
$('.page-content').append(html);
One thing you can do is copy the .player-wrapper before you write.
$(".overridebutton").on("click", function () {
var html = '<div class="override">Im a new div overriding everything except player-wrapper</div>';
var exception = $(".player-wrapper").html();
console.log(exception);
document.write(html + exception);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="everything">
<div class="sub-1">
Hello Im sub-1
</div>
<div class="sub-2">
Hello Im sub-2
</div>
<div class="sub-3">
Hello Im sub-3
</div>
<div class="player-wrapper">
I am player wrapper
</div>
</div>
<button class="overridebutton">Override</button>

improve code on updating content inside div

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");

Using a plugin on dynamically generated HTML

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.

Insert a form field into a popup page using jquery

I'm trying to insert a form field into a popup page. For some reason the form field doesn't get inserted. Any pointers. Pasted below is the code:
$(".ddlAddListinTo li").click(function () {
var urlstring = "../ActionTypes";
var ddlselectedVal = $(this).attr('id');
var $form = $("#frmPostToEmailReports");
var AgentId = $form.find("#AgentId").val();
var ReportName = $form.find("#ReportName").val();
var Params = $form.find("#Params").val();
if (ddlselectedVal != "None" && ddlselectedVal != "select") {
$.post(urlstring, { AgentId: AgentId, ReportName: ReportName, Params: Params },
function (data) {
window.open(urlstring);
$("#divfrmInfo").append($form);
});
} });
HTML for my popup window :
<html>
<head></head>
<body>
<h2>AddToCart</h2>
<form name="frmContact">
<div>
<div class="CartHeader">
<ul>
<li>
<span class="CartImage"></span>
<span class="Title">To Add Listing(s) to Cart</span>
<span class="SubTitle">Select your personal cart or add listings to a contact</span>
</li>
</ul>
</div>
**<div id="divfrmInfo"></div>**
</div>
</form>
</body></html>
Looking at it some more you could do something like this, in opener document.
$(".ddlAddListinTo li").click(function () {
...
function (data) {
$(window.open(urlstring)).load ( function() {
// Here "this" will be the window.
$(this.document).find("#divfrmInfo").append($form.clone())
});
}
This way you attach to load event for popup by jQuery.
Have a look at .clone() for the append part. If it is not cloned it will be "ripped" from your main document and placed inside the popup.
Old answer:
...
Here is a fiddle (With fixed typo/formatting).
Next problem is in your script you say:
$(".ddlAddListinTo li").click
However, there are no elements in DOM with class ddlAddListinTo.
OK, by comment:
after window.open(urlstring); you are still in DOM of document from where you opened the window. As such:
$("#divfrmInfo")
will look for an element in original document with that ID, not in the popup.
If you add something like this in the popup document*:
$(window).load(function() {
// Call function "fill()" in opener.
window.opener.fill(document);
});
And this in your opener document:
function fill(what) {
// Here "what" is document of popup.
what.getElementById("divfrmInfo").innerHTML = "TEST";
}
I think the selector in your AJAX callback is unable to get DOM elements in the popup. Try this:
var tmpWin = window.open(urlstring);
$(tmpWin.document).find("#divfrmInfo").append($form);
THe problem is you are tring to aceess the DOM of the spawned page before it is there. The window is loaded but the HTML is still being loaded at the time you are trying to access it. You will need to change the parent and popup page. On the parent page you will need a function to return what you want to populate the pop up with. On the popup page you will want to call the function on the parent page when the DOM is ready.
Something like:
Parent Page
//Add this OUTSIDE your document ready
function getContent(){
return $("#frmPostToEmailReports");
}
Popup
//Include Jquery in your prefered way
<script>
$(document).ready(function () {
$("#divfrmInfo").append(window.opener.getContent());
});
</script>
Alos make sure to remove where you attempt to pupulate in the success function. Also see: How to get element and html from window.open js function with jquery
Previous Useless Answer Below
See this answer to get you started.
Instance you will want something like:
$(".ddlAddListinTo li").click(function () {
var urlstring = "../ActionTypes";
var ddlselectedVal = $(this).attr('id');
var $form = $("#frmPostToEmailReports");
var AgentId = $form.find("#AgentId").val();
var ReportName = $form.find("#ReportName").val();
var Params = $form.find("#Params").val();
if (ddlselectedVal != "None" && ddlselectedVal != "select") {
$.post(urlstring, { AgentId: AgentId, ReportName: ReportName, Params: Params },
function (data) {
var popup = window.open(urlstring);
popup.document.$("#divfrmInfo").append($form);
});
} });

jQuery + Module Pattern: When to declare/query elements?

Typically, you don't start querying the DOM until the $(document).ready().
In both of the options below, the Widget is declared (and the elements are queried) outside of the $(document).ready().
Is this OK? Can I initialize the jQuery elements (as long as I'm not manipulating anything), OUTSIDE of the ready handler?
Would it be better to put this whole Widget definition inside the $(document).ready()?
Should I wait until the Widget.init() to query the elements?
Note: I'm brand new to JS design patterns, so please note if I'm missing something
Option1
Widget = {
ele : $('#ele'),
init : function(){ ... }
};
$(document).ready(function(){
Widget.init();
});
Option2
Widget = (function(){
var privateEle = $('#privateEle');
return {
publicEle: $('#publicEle'),
init: function(){ ... }
};
}());
$(document).ready(function(){
Widget.init();
});
What I would do:
var Widget = (function(){
var ele;
function init(_ele){
ele = _ele;
};
return {
init: init
};
})();
$(function(){
Widget.init( $('#foo') );
});
If your script is loaded before jquery, you will not see an error "undefined is not a function". But, if you perform a query before domReady, you could get unexpected result, ele = []
EDIT: btw.. put your <script> tags before </body> NOT within <head></head>
It won't work because at the time when you query the element, the element is not there yet, thus your query will return an empty jQuery selection. You can only query for elements when the DOM is ready.
what would work though is on of the following:
create the element outside $(document).ready(). note that you have to provide the full html or work with $(..).attr(x,y) and the likes.
Widget = {
ele : $("<div id='ele'>"),
....
}
or you can query the element on widget initialization.
Widget = {
ele : "#ele",
init : function(){
this.ele = $(this.ele);
...
}
}
You can include script just before body end tag.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Demo</title>
</head>
<body>
<!-- my HTML -->
<script src="../js/vendor/jquery-1.9.1.js"></script>
<script src="../js/vendor/jquery-migrate-1.1.1.js"></script>
<script src="../js/custom.js"></script>
</body>
</html>
DOM is ready (no need for $(document).ready):
/*custom.js */
var Widget = (function($){
var _$element;
return {
init: function(){
_$element = $('#myElementId');
// TODO - element is available from now on
};
};
}(jQuery));
Widget.init();

Categories

Resources