Smarty: cannot use the same template twice - javascript

I'm having the following Smary template (it's a file-tree, files are populated separately and then list_html is assigned to geberated file tree hrml)
<script>
$("#directory-list-root").on("click", "div.content", function() {
$("div.selected", "#directory-list-root").removeClass("selected");
$(this).addClass("selected");
// Check if directory is expanded
var node = $(this).parent("li.directory");
if (node.hasClass("expanded")) {
node.removeClass("expanded");
$(this).siblings("ul.container").hide();
} else {
node.addClass("expanded");
$(this).siblings("ul.container").show();
}
} );
</script>
<div id="directory-list-root">
<ul class="container" style="padding:5px" id="tree">
{$list_html}
</ul>
</div>
In the code it's used twice (in jquery-ui dialogs that are shown one after another). And the problem is that for the first time handling function is OK, but for the second click-handler is not working. If I remove tree from the first dialog then handlers in the second are assigned.
Do you know how that can be fixed?
Thank you in advance!
PS. I'm running Smarty 3.1.13 if that matters.

If the template is used twice there will be two elements with the id directory-list-root in the document, which is illegal. The result is that things won't work.
Instead of using a fixed id, use a dynamic one by incrementing an internal counter variable each time, e.g. by using {counter}:
<script>
$(function() {
{counter name=tree assign=uniqueId}
var $root = $("#directory-list-root-{$uniqueId}");
$root.on("click", /* etc */);
});
</script>
<div id="directory-list-root-{$uniqueId}">
<ul class="container" style="padding:5px" id="tree">
{$list_html}
</ul>
</div>

Related

Javascript - Functions Conflict

I use Filtrify plugin for filtering by advanced tag. This link is an example I used.
I focus this script on html file
$(function() {
$.filtrify("container", "placeHolder");
});
and
<div id="placeHolder"></div>
<ul id="container">...</ul>
When I add the script code below on html file, it only show <ul id="container"> not show <div id="placeHolder">.
My script I added
function $(element) {
return document.getElementById(element);
}
Please explain why and how can I add the script above?
You can't have jQuery and your own function both providing a value for a variable called $.
Rename one of the $ functions.

Replace html in $(this) element with another html (jQuery)

I want to replace the content in the current element with and html string taken out of an object.
It has to work dynamically regardless of what div, p...etc it is in.
<div id="content">
<h5><script>$(this).append(en.login_terms_and_conditions);</script></h5>
</div>
It's possible to do what you've shown, but it's probably not a good idea. You'd use $(document.body.lastElementChild):
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
// Presumably you have something defining that `en` variable and the object it refers to:
var en = {
login_terms_and_conditions: "terms and conditions here"
};
</script>
<p>one</p>
<p>two</p>
<p>three</p>
<div id="content">
<script>$(document.body.lastElementChild).html(en.login_terms_and_conditions);</script>
</div>
<p>four</p>
<p>five</p>
<p>six</p>
...or of course, just $("#content") if that id is always on the element.
This works because the element is added to the DOM as of when your script runs (the details on that are complicated, but covered in the spec), even though the element's end tag has not yet been parsed.
I wouldn't do that, though, for a couple of reasons, not least that if you're doing this with jQuery, you have to load jQuery prior to that element, which holds up the rendering of your page. You could fix that by not using jQuery for this bit:
<script>
// Presumably you have something defining that `en` variable and the object it refers to:
var en = {
login_terms_and_conditions: "terms and conditions here"
};
</script>
<p>one</p>
<p>two</p>
<p>three</p>
<div id="content">
<script>document.body.lastElementChild.innerHTML = en.login_terms_and_conditions;</script>
</div>
<p>four</p>
<p>five</p>
<p>six</p>
...but it still seems like there are simpler solutions, like just document.write-ing the content, or using server-side templating.
Your example is not quite how jQuery works. The location of the script is irrelevant to the scope of this when attempting to affect an element.
Instead you need to select the #content element directly, then call html() with the value of the login_terms_and_conditions property. Try this:
var en = {
login_terms_and_conditions: '<h2>fizz buzz</h2>'
}
$(function() {
$('#content').html(en.login_terms_and_conditions);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="content">
<h5>foo bar</h5>
</div>
First, this does not work as you want. You have to select an element first and then refer to it with this.
Second, even if you would want to add an object key directly into html, that's not possible. ( is possible in JSX but that's another thing :) ).
Third, to make it more dynamic (as I understood you want), you can add some specific data-attributes to your html elements. For example a data-obj='content' for the content and so on. Then, you can iterate your en object and add en[key] value to it's respective html element with the data-obj.
See below
const en = {
title: 'Title in english',
content: 'Some content in english here <br/>Some content in english here ',
link: 'Link text'
}
for (let key in en) {
if( en.hasOwnProperty(key) ) {
let element = $(`[data-obj='${key}']`)
element.html(en[key])
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="content">
<h5 data-obj="title"></h5>
<p data-obj="content"></p>
<a data-obj="link"></a>
</div>
If you want to target by id, then you could try something like this:
$("#content").html(en.login_terms_and_conditions);

How do I move these elements in DOM

I don't want to change HTML because I want to leave the display the way it is for default view and want to move them in second view. I want to know how I can dynamically order the class of a div.
I want to do this via button click. I have adEventListener() for 'click' where I am doing something and the move logic would go inside this event listener.
I understand that I can get these divs, remove from their parents and place it where I want. But I do not know how to do these for each of them since I have multiple lis. I am struggling with the loop so that I can do these for each li. I need to do this using pure JS and not jQuery.
<ul>
<li>
<div>
<div class="a">
<div class="b">
<a class="c">
<div class="d"></div>
<div class="e">
<div class="f"></div> // this is the first item that I want to move
</div>
<div class="g"></div> // this is the second item that I want to move
</a>
</div>
<div class= "h"></div> // I want above mentioned divs to be before this div
</div>
</div>
</li>
//There are multiples lis
<li></li>
Assuming you would like to do this on load of the page, you could solve your problem with the following JQuery DOM manipulations:
$(document).ready(function(){
$("ul .a").each(function(index, element){
$current_div_a = $(element);
$div_h = $current_div_a.find(".h");
$div_f = $current_div_a.find(".f");
$div_f.clone().insertBefore($div_h);
$div_f.remove();
$div_g = $current_div_a.find(".g");
$div_g.clone().insertBefore($div_h);
$div_g.remove();
})
});
You can test it out on this demo.
I strongly advise against this way of doing it though. I guess it's also the reason why your question got some downvotes too. Just modifying your HTML keeps your code clean, maintainable and clearer for anyone else starting to work on your project. Keeping backwards compatibility for your code as much as possible will cause maintainability problems later.
I ended up using
var list = document.querySelectorAll("ul li");
for (var item of list) {
let fClass = item.querySelector(".f");
fClass.parentNode.removeChild(fClass);
let parentOfFirstChildAfterWhichIwantMyF = item.querySelector(//selector for parentOfFirstChildAfterWhichIwantMyF);
parentOfFirstChildAfterWhichIwantMyF.insertAdjacentElement("beforeend", fClass);
}

Get the innerhtml of element which is loading at run time

This is div which loads elements at rum time.
<div class="name" id="projct_name"></div>
after loading elements its becomes:-
<div id="projct_name" class="name">
<div>
<span >Proof testers</span>
</div>
</div>
I want the value of span.
$(document).ready(function() {
var prodct_name=$('#projct_name').find('div').find('span').html();
alert(prodct_name);
});
Each time page load get the alert null value because elements loads after alert.
I want to delay my js code so that all elements of page loads before my code run. It can be possible??
Try the below code:-
function pageLoadCompelet(){
var prodct_name=$('#projct_name').find('div').find('span').html();
alert(prodct_name);
}
And call this function on window.onload :-
window.onload=pageLoadCompelet;
I think Jquery Initialize will solve your issue.
Step 1: Insert this in the head-section of your page:
<script src="https://raw.githubusercontent.com/AdamPietrasiak/jquery.initialize/master/jquery.initialize.js"></script>
Step 2: Place the following javascript below or above the other code you already tried:
$("#projct_name span").initialize( function(){
alert($(this).html());
});
The plugin uses MutationObserver which is a really robust way of handling DOM changes.

Why can't I retrieve "this" dom element without onclick?

I have a very basic question about using the "this" keyword to retrieve a DOM element.
Consider the following HTML/Javascript:
<div class="container">
<div class="regular-div">
<script type="text/javascript">
console.log(this);
</script>
Here is a div withOUT onclick
</div>
<div class="onclick-div" onclick="console.log(this)">
Here is a div with onclick
</div>
</div>
While clicking the "onclick-div" it does return the DOM object for that div. However, the console.log event calls 'this' indirectly in the "regular-div" and returns window.
Is it possible to get "this" DOM object when 'this' is called indirectly? My purpose is I want to fire a function in line in the HTML, but need to send the function "this". Here's an example of what i'm trying to do:
<div class="container">
<div class="regular-div">
<script type="text/javascript">
loadSomeHTML(this, varA, varB, varC);
</script>
</div>
</div>
Thanks everyone for any clarification of how "this" works in the above context.
In your first example, the script isn't in any way associated with the div. It's just been output within the div, but it's not connected to it. The script runs as the page is being parsed.
Is it possible to get "this" DOM object without a user interaction?
If you mean inline with the parsing of the HTML, you could do this:
<div class="container">
<div class="regular-div">
Here is a div withOUT onclick
</div>
<script type="text/javascript">
(function() {
var list = document.querySelectorAll('div');
console.log(list[list.length - 1]);
})();
</script>
</div>
Note that the script tag is immediately after the ending </div> tag for the div you're trying to target. The script gets what's currently the last div in the document as of when the script runs. Or of course you could identify the div in some way (a class, for instance) and use that (and then potentially remove it so you could do it again later in the document).
It looks dodgy, but it's perfectly valid cross-browser, and was even recommended at one stage by the Google Closure Library engineers.
Live Example:
<div class="container">
<div class="regular-div">
Here is a div withOUT onclick (look in console for result)
</div>
<script type="text/javascript">
(function() {
var list = document.querySelectorAll('div');
console.log(list[list.length - 1]);
})();
</script>
</div>
Example using a class we move:
<div class="container">
<div class="target-me">
The first div
</div>
<script type="text/javascript">
(function() {
var div = document.querySelector(".target-me");
div.classList.remove("target-me");
console.log(div);
})();
</script>
<div class="target-me">
The second div
</div>
<script type="text/javascript">
(function() {
var div = document.querySelector(".target-me");
div.classList.remove("target-me");
console.log(div);
})();
</script>
</div>
Note I didn't use id, because if we used an id and JavaScript wasn't enabled, we'd end up with an invalid document (because it would have multiple elements with the same id). It'd be fine if JavaScript were enabled (because we'd remove the id from earlier ones before later ones were created), but...
Javascript has no implicit connection to the HTML DOM. The reason why onclick works the way you want is because the HTML DOM implementation passes the element to the js callback. You need to do something similar in your other case. One way to do this is:
<div class="container">
<div class="regular-div" id="mydiv">
<script type="text/javascript">
loadSomeHTML("#mydiv", varA, varB, varC);
</script>
</div>
</div>
Then your js implementation does the lookup to find the element:
function loadSomeHTML(selector, varA, varB, varC) {
var el = document.querySelector(selector);
// now el is where you want to insert your HTML
// ...
}
The code inside the script tag doesn't have any connection with the tag itself. this should, basically, return the object on which the current function was called, or the global environment, window. In the first div, the code is just executed, on no object, so window is returned. The value of onclick, on the other hand, is treated as a function (with even some parameters, like e), that gets called on the element with the attribute. So, the code in the script element is executed in the global scope, whereas the one in the attribute is in a function scope (that's why all vars are shared across script tags).
As explained in How may I reference the script tag that loaded the currently-executing script?, the proper way of obtaining a reference to the script element whose code is being executed is
document.currentScript;
Then, to get the parent node of that element, use
document.currentScript.parentNode;
<div class="container">
<div id="regular-div">
<script type="text/javascript">
alert('#' + document.currentScript.parentNode.id);
</script>
Here is a div withOUT onclick
</div>
</div>

Categories

Resources