script code doesn't run inside foreach loop? - javascript

<!--language: lang-html-->
#foreach (var book in Model.Category.Books)
{
<div class="rate-star-#book.Id"></div>
<script>
$(".rate-star-#book.Id").stars({ stars:5, readonly:false});
</script>
}
A brief explanation about what I'm trying to do:
This script code inside the loop is one of the star rating plugins that I need to implement for books on the page. The problem here is that I need to include jquery code further up in the body but since JQuery library loads later than the script code, I get "$ is not defined" error.
What Have I tried:
I tried to implement the solution on this page
[Handling code which relies on jQuery before jQuery is loaded written by Ashkan Mobayen Khiabani. I put the code inside a function. The function is called at the bottom of the body. It is supposed to be called as many times as it's created in per iteration. But since it's called only once at the bottom the other created functions don't run and only one book gets affected by the function as a result.
<!--language: lang-html-->
#foreach (var book in Model.Category.Books)
{
<div class="rate-star-#book.Id"></div>
<script>
function rateStar{
$(".rate-star-#book.Id").stars({ stars:5, readonly:false});
</script>
}
}
#section scripts
{
<script>
rateStar();
</script>
}
So how to do that function gets called as many times as it's created in the document?

in Views/Shared open _Layout.cshtml and in the head tag create a script tag and create an array (lets name it postJquery:
<head>
...
<script>var postJquery = [];</script>
...
</head>
Now in the same file (_Layout.cshtml) go to the bottom and add this code before ending of body tag:
<script>for(var i=0;i<postJquery.length;i++) postJquery[i]();</script> //just ad this line
</body>
Now anywhere that you need to run a code that depends on jquery just add it to a function and add it to postJquery array and it will run after jQuery is loaded like this:
postJquery.push(function(){
//your code goes here
});
for example, your case would be:
#foreach (var book in Model.Category.Books)
{
<div class="rate-star-#book.Id"></div>
<script>
postJquery.push(function(){
$(".rate-star-#book.Id").stars({ stars:5, readonly:false});
});
</script>
}
}
The code above will run just fine, but there is what I don't like about it that the script tag and its content will be repeated for each book item, for example, if you have 20 books in your loop, the following code will be repeated 20 times (of course book id will change for each one):
<script>
postJquery.push(function(){
$(".rate-star-#book.Id").stars({ stars:5, readonly:false});
});
</script>
So instead I would do something like this:
#foreach (var book in Model.Category.Books)
{
<div class="rate-star" data-id="#book.Id"></div>
}
<script>
postJquery.push(function(){
$(".rate-star").stars({ stars:5, readonly:false});
});
</script>
As I don't know about .stars if it should be used on a single element (and clicking on above code effects all items) you could do it like this:
#foreach (var book in Model.Category.Books)
{
<div class="rate-star" data-id="#book.Id"></div>
}
<script>
postJquery.push(function(){
$(".rate-star").each(function(){
$(this).stars({ stars:5, readonly:false});
});
});
</script>

Related

How do I change placeholder content in javascript per page

How do I update content loaded with Jquery .load() with javascript?
I'm using two placeholders on every page: one with the navigation bar, and one with the main skeleton of the content, like this:
<body>
<div id="nav-placeholder">
</div>
<div id="content-placeholder">
</div>
</body>
The nav bar and content are both in seperate files and are loaded into the pages with an external javascript file like this:
$(function(){
$("#nav-placeholder").load("nav.html");
});
$(function(){
$("#content-placeholder").load("content.html");
});
So far, it all works nicely. Now, I'm trying to alter the content separately for each page (with JS)
Part of content.html is for example
<h2 id="subheader1">Title</h2>
I'm trying to change the #subheader1 content in the javascript file like so:
$(function(){
$("#nav-placeholder").load("nav.html");
});
$(function(){
$("#content-placeholder").load("content.html");
});
$(document).ready(function() {
document.getElementById("subheader1").outerHTML = "test" ;
});
but that doesn't work (this is aimed at all pages, but it still doesn't work). Probably because it's only seeing the placeholder DIV in index.html and not it's content?
I tried placing the subheader1 div in the index.html to test, and then it did work, but that would take away the efficiency of the placeholder.
Is there any way to do this (or another way to be more efficient with pages with the same (DIV) layout but different text?)
Thanks!
The load method is not synchronous, so
$(document).ready(function() {
document.getElementById("subheader1").outerHTML = "test" ;
});
is executed before the html is loaded in the page.
The doc suggest using a callback function.
it is executed after post-processing and HTML insertion has been performed
I had success using this in my js file:
$(document).ready(function() {
$(function(){
$("#nav-placeholder").load("./nav.html", function() {
document.getElementById("insideNav").outerHTML = "It works !" ;
});
});
});
with <h2 id="insideNav">Original Nav Bar</h2> in my nav.html.

How do I insert an additional JS script for each element in an array using jQuery?

I'm trying to add a "Book Preview" button using the Google Embedded Viewer API. I want to add the button to each book result the user gets. When I add the script to the list using .append, the script erases everything and when the I submit a search query everything disappears and I only see the preview button.
I tried putting the <script> part in the HTML file, but when I did that the function appeared as plain text. I also tried putting the script in a separate file and using $.getScript, but that isn't doing anything. I also tried appending the script to a separate div, but that didn't work either. When I put the script directly in the HTML file, it doesn't erase everything but also doesn't work with the array data.
main JS file:
function displayResults(responseJson, maxResults) {
console.log(`displayResults ran`);
console.log(responseJson);
$('#results-list').empty();
for (let i = 0; i < responseJson.items.length & i < maxResults; i++){
$('#results-list').append(
`
<li>
<p>${responseJson.items[i].volumeInfo.industryIdentifiers[1].identifier}</p>
<img src="${responseJson.items[i].volumeInfo.imageLinks.thumbnail} alt="The book">
<h3>${responseJson.items[i].volumeInfo.title}</h3>
<h2>${responseJson.items[i].volumeInfo.authors}</h2>
<p>${responseJson.items[i].volumeInfo.description}</p>
Buy this Book
<div></div>
<input type="submit" class="preview-button" id="book-preview" value="Preview This Book">
</li>
`);
$.getScript("book-viewer-index.js")
};
$('#search-results').removeClass('hidden');
};
linked file/button code:
<div>
<script type="text/javascript"
src="https://books.google.com/books/previewlib.js"></script>
<script type="text/javascript">
GBS_insertPreviewButtonPopup('ISBN:0738531367');
</script>
})
</div>
The expected result is a button under each book search result that will display the hard-coded book preview. There is currently no actual result. I added in the "preview book" button in case I have to do it that way but that's not actually how I want it.
https://books.google.com/books/previewlib.js only needs to be included once before your loop starts.
You just need to call GBS_insertPreviewButtonPopup for each element you create in the loop, you don't need to inject a script block into the html to call it.
Straight after you call the append to the results-list you can call the GBS_insertPreviewButtonPopup in your loop.

Link to a page in HTML and immediately call a specific Javascript function

I have two HTML files like this:
file1.html:
section 1 of file2
section 2 of file2
file2.html:
<script>
function showSection(sectionId) {
section = document.getElementById(sectionId);
section.style.display = "block";
}
</script>
<style>
section { display: none; }
</style>
...
<section id="1">
Section 1
</section>
<section id="2">
Section 2
</section>
On clicking one of link in file1, I would like to immediately call a Javascript function that only shows section 1 or 2, depending on which link was closed. How can I do this? The issue with the above code is that it calls a function which is not defined in file1.html
You can not call functions in other frames, except for specific APIs like window.postMessage(). But this ist not what you want, I think.
if you want to execute a function when the page loads you can simply execute it in a <script> tag, or listen to the DOMContentLoaded event, which will fire when the document has been constructed.

Javascript inside Mustache.js template

I have a list of users coming from back-end and I append each one of them to my HTML page like below. My goal is to have javascript rating system for every user.
<head>
<link href="/css/rateyo.css"/>
<script src="/js/rateyo.js"/>
<script type="text/template" id="mustache-template">
{{#user}}
<li>
{{name}}
<div id="rating"></div>
</li>
{{/user}}
</script>
<script>
$("#rating").rateYo().on("rateyo.set", function (e, data) {
});
</script>
</head>
<body>
<ul>
<!-- All the individual users will be in their own li element here -->
</ul>
</body>
Everything is working except my rating script. It should make five stars next to each user. But I heard that you can't put scripts inside templates, is it correct? If I move that <div id="rating"/> to somewhere else it works like it's meant and shows the stars.
What should I do? I can't really put that script outside of my templates.
You can add your function to the object you are trying to parse with the template, and then call the function in your template.
var userlist = {
user: [
{name: 'name nameson', doRating: function() {someOtherFunction();}},
{name: 'some otherguy', doRating: function() {someOtherFunction();}}
]
};
var someOtherFunction = function() {
$("#rating").rateYo().on("rateyo.set", function (e, data) {
//Do stuff?
});
}
<script type="text/template" id="mustache-template">
{{#user}}<li>{{name}} <div id="rating"></div></li>{{/user}}{{doRating}};
</script>
Or you could of course calculate the rating on beforehand, and implement some sort of {{user.rating}} and use that to generate in your template.
Or as I look closer, you could just add the listener after mustache is done rendering. Since the div#rating would then be available (which should really be a class btw).
This would be my approach at least.

Javascript Ajax JQuery

Here's my issue.
I have a javascript function that update a div when i click the proper link. And it is working.
Since i have cliked the link my div content is updated with another Javascript. This time to close it.
Its fairly simple but i cant get it to work and i dont know why!
Here is the code that is in the page when it load for the first time
The div id config_window
<div id="config_window" class="config_window">
<div id="conception" class="conception">Conception et design graphique Zéro Gravité.
</div>
<div id="admin_btn"class="admin_btn">administration.</div>
<div id="test">test</div>
</div>
Now the Javascript that call for the update inside that div
<script language="javascript" type="text/javascript">
$("#admin_btn").click(
function(){
$('#config_window').addClass('config_open');
config_set('config_window','open','var')
}
);
</script>
So far it's working my div is getting updated and i see the new content. The new content is
<div id="conception" class="conception">Conception et design graphique Zéro Gravité.
</div>
<div id="admin_btn_x" class="admin_btn">Terminer.</div>
<script language="javascript" type="text/javascript">
$("#admin_btn_x").click(
function(){
$('#config_window').removeClass('config_open');
config_set('config_window','close','var')
}
);
</script>
i was expecting that same function to work but its not!! and i dont get why since the first one is.
Could it be becuse my second script is in the div that get updated??
Thanks!
I suspect it's because the element that the second handler is supposed to apply to doesn't exist until after the DIV is updated and the function applying the handler is executed before the DIV is updated -- therefore the handler is not applied. You might want to try using the live handlers for the click event so that it will apply to all elements matching the selector no matter when the element is added. You can add both handlers on page load and they will apply to the elements with those ids whether they are added dynamically or not.
<script type="text/javascript">
$("#admin_btn").live('click', function(){
$('#config_window').addClass('config_open');
config_set('config_window','open','var')
});
);
$('#admin_btn_x').live('click', function() {
$('#config_window').removeClass('config_open');
config_set('config_window','close','var')
});
</script>
Is there a reason you add divide the function into two scripts? I would change your script to something like this:
<script type="text/javascript">
$(document).ready(function() {
$('#config_window').hide(); // just in case
$('#admin_btn').bind("click", function() {
if($('#config_window').is(':hidden')){
$('#config_window').show();
config_set('config_window','open','var')
} else {
$('#config_window').hide();
config_set('config_window','close','var')
}
});
});
</script>

Categories