I have looked through several posts but have not found an answer that actually solves this issue so I am asking whilst trying to provide the most pertinent details.
I have a very simple script file called custom.js ...
function AddListItemToUnorderedList(pageCode, menuName) {
$('.child_nav').append('<li><span>' + menuName + '</span></li>');
}
I have made reference to that script in my partial page.
<script type="text/javascript" src="~/Scripts/custom.js"></script>
#{
Layout = null;
}
<ul class="child_nav" style="display: none;"></ul>
#foreach (var item in ViewBag.MenuItems)
{
#Html.Raw("<script type='text/javascript'>")
#Html.Raw("AddListItemToUnorderedList('")
#item.PageCode
#Html.Raw("', '")
#item.MenuName
#Html.Raw("');")
#Html.Raw("</script>")
}
The above code works but it looks terrible AND it adds a script tag to the markup for each item in the MenuItems collection. The MenuItems collection simply contains a list of two strings correlating to my menu's display name and html link....consider this to be populated with something as simple as Test Page for the name and myTestPage.com for the link.
I have see some shortcut syntax like this
#: AddListItemToUnorderedList(item.PageCode, item.MenuName)
however, I am not able to get that to work no matter what I try.
Any clear suggestions that work that will allow me to make a direct call to the JavaScript function passing in the two properties from the ViewBag where I don't have to create the script tags and use #Html.Raw?
Something like the below should work. Pull out the script tags from the foreach, and then reference the javascript. You'll also have to put <text></text> tags around the javascript and quotes around the variables so they will transfer correctly:
<script type='text/javascript'>
#foreach (var item in ViewBag.MenuItems)
{
<text>AddListItemToUnorderedList('#item.PageCode', '#item.MenuName')</text>
}
</script>
Related
I have to generate some li element automatically and the way I was doing it it through a function that return text inside a loop, something like this:
function getLi(data) {
return '<li>' + data + '</li>';
}
then I found a better way to do it by writing html inside a div:
<div style="display:none;" id="Template">
<li id="value"></li>
</div>
and then I would change the id and value get the html and reset the element to original state:
var element = $("#value");
element.html(data);
element.attr('id', getNewId());
var htmlText = $("#Template").html();
element.html('');
element.attr('id', 'value');
return htmlText;
then I was reading on script template
and I figured this could be a better way of doing it,
However apply the previous code didn't work as the inner elements didn't exist according to this article
so how can I apply this?
EDIT:
I put inside a ul tag, I use this method to get the items dynamically
EDIT2:
<li>
<a href="#" >
<span>
<span>
some text
</span>
</span>
</li>
this isn't necessarily what I have but something along the way
Edit3:
my ul does not exist orgialy it's generated dynamically
I insist this is not a duplicate I want to know how to use a template with some dynamic variables
You could do the following way. It's clean, reusable and readable.
//A function that would return an item object
function buildItem(content, id) {
return $("<li/>", {
id: id,
html: content
});
}
In your loop, you could do the following. Do not append each LI inside the loop as DOM manipulation is costly. Hence, generate each item and stack up an object like below.
var $items = $();
// loop begin
var contents = ['<span><span>', data, '</span></span>'].join('');
var $item = buildItem(contents, getNewId());
$items.add($item);
// loop end
Just outside the loop. append those generated LIs to the desired UL, like below.
$("ul").append($items);
This is what I'd do and I am sure there are many better ways. Hope that helps.
One option is to upgrade to a modern JavaScript framework like AngularJS and then you could do it in one line using ng-repeat.
This would serve your purpose and make you more money as a developer.
If you're going to repeat this, use a templating system. Like {{ mustache }} or Handlebars.js.
If not, you can do this.
<ul>
<li class="hidden"></li>
</ul>
And in Javascript
$('ul .hidden').clone().removeClass('hidden').appendTo('ul');
And CSS, of course
.hidden { display:none }
Try this...
function getLi(data,ID) {
return $('<li id = "'+ ID + '">' + data + '</li>');
}
It returns javascript objest of Li..and you append it where ever you need.
what you need is using jquery templates, in the bellow link you can use good one which I'm using.
you create your template and prepare you JASON object of data.
after that every thing will be ready in one function call, more details in this link.
jquery.tmpl
hope this helps you and any one come to here in future..
I have an asp.net 4.5 (C#) page on VS2013. In this page, I am using a loop to itrate threw some of my objects. for each object(product) I have a textbox (input with type=textbox) which I use jquery on to make it a spinner .
I need this inside the loop for every product since I want each spinner to have it's parameters from the object (min, max, step size, is decimal etc.).
The loop goes something like that:
foreach ( Product product in getCart().ItemsList() ) {
String spinnerId = "spinner_" + product.Code;%>
<input id="<%:spinnerId %>" name="<%:product.Code%>">
<script type="text/javascript" language="javascript">
setSpinner('<%:spinnerId%>','<%:product.min%>','<%:product.max%>','<%product.step%>');
</script>
<%}%>
and in the head of the page I have:
function setSpinner(id,minVal,maxVal,stepVal){
j("#"+id).spinner({
min: minVal,
max: maxVal,
step: stepVal,
});
}
The problem is, that when I have the loop goes over a few times (10-15) the page loads very purley and the "onready" functions are taking a few seconds to perform, which meaning some fields that needs to be hidden are shown for 2 seconds and only than disaperas (this includes ajaxcontroltoolkit controls such as popupextender panel etc.).
To make this simple, the javascript code itself makes no matter.
If you try something like this:
<%for (int i=0;i<100;i++){%>
<script type="text/javascript" lang="javascript">
</script>
<%}%>
The same problem occures.
It seemes that even an empty javascript block is making the page take a long time to complete, if youe use it multiple times.
Why are 50\100 empty javascript blocks making the page lag so bad? and what can I do to solve this, considering I have to use the javascript code with each of the my objects data?
Try adding the info you need in data- HTML attributes, and calling javascript one single time. Something like
foreach ( Product product in getCart().ItemsList() ) {
String spinnerId = "spinner_" + product.Code;%>
<input id="<%:spinnerId %>" class="spinner" name="<%:product.Code%>" data-min="<%:product.min%>" data-max="<%:product.max%>" data-step="<%:product.step%>">
<%}%>
Then iterate on the "spinner" class inputs with jQuery:
$("input.spinner").each(function(intput){
$(this).spinner({
min: $(this).data('min'),
max: $(this).data('max'),
step: $(this).data('step'),
});
});
look at #David's ans first that surely is a better approach
as cleared by #roland this is ugly.
even if you need to inject js into the web page. inject a js object preferably and array containing all the objects and then inside a single block on page load iterate through it and get your work done.
var ps = getCart().ItemsList().Select(p=>new {
p.Id
/...All your propertiese.../
});
now inject ps inside the web page / script tag using any json library like Newtonsoft.Json.
var jsonString = JsonConvert.SerializeObject(ps);
I know this has been adressed before, but I can't seem to get it working for me.
I am trying to create a football pitch with editable players via HTML/JavaScript/jQuery.
I can produce the field the first time when loading the page without any problems. The code looks like this:
<div id="pitch" class="updateAble">
<script type="text/javascript">
appBuilder(team1, team2);
</script></div>
appBuilder() looks like this:
var appBuilder = function (team1, team2) {
team1.Display();
team2.Display(); }
It simply creates the players on the pitch for both teams. As it does. I now want to push an input-button to call a function appUpdate(), which deletes the content of #pitch and puts the appBuilder()-part in again as to renew it (if I changed or added players):
var appUpdate = function () {
var newContent = "<script type='text/javascript'>appBuilder(team1, team2);</script>";
var updateItem = $('#pitch');
updateItem.empty();
updateItem.append(newContent);}
Here is what drives me nuts: It seems to work just fine up to and including the empty()-function. So the code has to be fine.
But when I try to append newContent to the #pitch-DIV, the programm seems to completely delete everything inside <head> and <body> it recreates a clean html-file (with empty html-, head-, body-tags) and inserts my players inside <body>.
Any ideas as to why it is doing that?
Thanks in advance!
UPADTE: The solution was a rookie mistake (which is fitting, since I'm a rookie). The Team.Display()-method was trying to do a document.write() call. As I learned: If you call document.write once the document is fully loaded, it will delete your site. Thanks to jfriend for the solution! :)
If you call document.write() AFTER the document has finished loading, then it will clear the current document and create a new empty one.
What you need to do is use DOM insertion operations rather than document.write() to add/change content in the DOM once the document has already loaded.
My guess is that the .Display() method is using document.write() and you need to change the way it works to insert content into a parent node rather than write it into the current position.
Some ways to insert content:
var newNode = document.createElement("div");
node.appendChild(newNode);
node.innerHTML = "<div>My Content</div>";
Or, if you're using jQuery, you can use it's wrappers for this:
obj.append("<div>My Content</div>");
obj.html("<div>My Content</div>");
.html() would empty and fill the div at once. Have you tried that ?
updateItem.html(newContent);
I proposed a JQuery replacement for your code that does what you want, ion the style of your own typing.
Note that I kept the .html() call to mimic your "empty()" function, but it is not necessary. Simply put he code in the append, straight into the html() et get rid of the extra unnecessary remaing bit of code.
My code replacement, as a 100% functioning .html file. Hope it helps, cheers.
<html>
<header>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
var appBuilder = function (team1, team2) {
//team1.Display();
//team2.Display();
}
var team1, team2;
</script>
</header>
<body>
<div id="pitch" class="updateAble">
<script type="text/javascript">
appBuilder(team1, team2); // Original code to be updated
</script>
</div>
<script>
var appUpdate = function () {
$("#pitch").html("<!-- Old javscript code has been flushed -->").append($("<script />", {
html: "appBuilder(team1, team2); // brand new, replaced code"
}));
}
appUpdate();
</script>
</body>
</html>
To save me a lot of work editing a number in when adding a document to a site I decided to use javascript to count the number of elements with a class doc .
I am two main problems:
There is trouble displaying the variable. I initially thought this was because I hadn't added function, however when I tried adding this the variable was still not displayed.
The elements with the class I want to count are on another page and I have no idea how to link to it. For this I have tried var x = $('URL: /*pageURL*/ .doc').length; which hasn't worked.
Essentially I want the total elements with said class name and this to be displayed in a span element.
Currently I have something similar to what's displayed below:
<script>
var Items = $('.doc').length;
document.getElementById("display").innerHTML=Items;
</script>
<span id="display"></span>
Found an example of something similar here where the total numbers of articles are displayed.
Edit:
#ian
This code will be added to the homepage, domain.net/home.html. I want to link to the page containing this documents, domain.net/documents.html. I've seen this done somewhere before and if I remember correctly they used url:domainname.com/count somewhere in their code. Hope this helps.
Here is a jQuery call to retrieve the url "./" (this page) and parse the resulting data for all elements with class "lsep" "$('.lsep', data)". You should get back a number greater than 5 or so if you run this from within your debug console of your browser.
$.get("./", function(data, textStatus, jqXHR)
{
console.log("Instances of class: " + $('.lsep', data).length)
});
One important thing to remember is that you will run into issues if the URL your are trying to call is not in the same origin.
Here's an updated snippet of code to do what you're describing:
$(document).ready(
function ()
{
//var url = "/document.html" //this is what you'd have for url
//var container = $("#display"); //this is what you'd have for container
//var className = '.data'; //this is what you'd have for className
var url = "./"; //the document you want to parse
var container = $("#question-header"); //the container to update
var className = '.lsep'; //the class to search for
$.get(url, function (data, textStatus, jqXHR) {
$(container).html($(className, data).length);
});
}
);
If you run the above code from your browser's debug console it will replace the question header text of "Counting classes on another page and displaying them" with the count of instances the class name ".lsep" is used.
First, you have to wait until the document is ready before manipulating DOM elements, unless your code is placed after the definition of the elements you manipulate, wich is not the case in your example. You can pass a function to the $ and it will run it only when the document is ready.
$(function () {
//html() allows to set the innerHTML property of an element
$('#display').html($('.doc').length);
});
Now, if your elements belongs to another document, that obviously won't work. However, if you have used window.open to open another window wich holds the document that contains the .doc elements, you could put the above script in that page, and rely on window.opener to reference the span in the parent's window.
$('#display', opener.document.body).html($('.doc').length);
Another alternative would be to use ajax to access the content of the other page. Here, data will contain the HTML of the your_other_page.html document, wich you can then manipulate like a DOM structure using jQuery.
$.get('your_other_page.html', function(data) {
$('#display').html($('.doc', data).length);
});
I have a jsp page that updates what is listed based on the selection in a box.
<form:select path="Value" id="select" onchange="update()" items="${Values}" />
And in another file the corresponding update function that populates based on what you selected and the item. This works for one box, but I need to have multiple boxes, but copying the code into a for loop generates multiple boxes, but the update function only points to the id of the object "select". I want to create a way to have select to be variable, so that it generates multiple objects with different values so that they don't point to the same thing.
My thought was to just create a var and then have it count, so that at id="select" can force it to create different objects... but the update function reads from the jsp with
var Val = $('#select option:selected').val();
In order to make them match, I need to pass parameters into the update() function, but when I fill in update method with parameters, the JSP can no longer call it. I tried
Update(var n) { //code here}
and
Update(int n) {//Code here}
But when the JSP statement runs update(//ValueIwant), it always throws the error of not finding the method.
So my question is , how can I pass a parameter from a jsp page to the javascript function dynamically without hardcoding all the values.
i figured it out. It's pretty simple. Just call the function(Parameters) from JSP, but in the javascript, the method is just declared with the parameter not having a type.
Function Myfunction (N)
{
//code
}
In this specific situation, the javascript keyword this can be used to pass along the reference of the element.
Staying as close as possible with provided code (including jQuery use), this would be:
<form:select path="Value" id="select" onchange="update(this)" items="${Values}" />
<!-- 3 more times; id should be changed and kept unique -->
<!-- ... -->
<script type="text/javascript">
function update(srcElement) {
var Val = $(srcElement).find('option:selected').val();
// want to make sure it's OK so far?
console.log(Val);
}
</script>
Now, in the general case, as others have mentioned, it's essentially a question of how you use the JSP tags so as to generate HTML (and here embedded javascript) that does what you want it to do.
I haven't practiced Spring MVC (I assume that's what is being used here), but in pseudo-code, this could look like:
<!-- remember? this is *pseudo-code*,
for I ignore the form:select capabilities,
specifically towards runtime expressions like ${i}
-->
<% for(int i= 0; i<4 ; i++) { %>
<%-- maybe the following line is not 100% OK;
fix it according to your taglib documentation --%>
<form:select path="Value" id="select${i}"
onchange="update(${i})" items="${Values}" />
<% } %>
<script type="text/javascript">
function update(index) {
var Val = $('#select' + index + ' option:selected').val();
// want to make sure it's OK so far?
console.log(Val);
}
</script>