I am building a search query which gives me results.
I have a template ready for the item inside a hidden div. What I want to do is replicate the template n number of times using jQuery.
So For example:
I search for flights and I get 5 search results, I need to replicate the below div template 5 Times
<div id="oneWayFlightElement" class="displayNone">
<div id="flightIndex1" class="flightDetailElement boxShadowTheme">
<div id="flightDetailsLeftPanel1" class="flightDetailsLeftPanel marginBottom10">
<div class="fullWidth marginTop10">
<span id="flightPriceLabel1" class="headerFontStyle fullWidth boldFont">Rs 9500.00</span><hr/>
<div id="homeToDestination1" class="flightBlockStyle">
<span id="flightNumberFromHome1" class="fontSize16">AI-202</span><br/>
<span id="flightRouteFromHome1" class="fontSize26">PNQ > DEL</span><br/>
<span id="flightDepartTimeFromHome1" class="fontSize26">Depart: 10.00 AM</span><br/>
<span id="flightArrivalTimeFromHome1" class="fontSize26">Arrive: 12.00 PM</span><br/>
</div>
<div id="destinationToHome1" class="flightBlockStyle">
<span id="flightNumberToHome1" class="fontSize16">AI-202</span><br/>
<span id="flightRouteToHome1" class="fontSize26">PNQ > DEL</span><br/>
<span id="flightDepartTimeToHome1" class="fontSize26">Depart: 10.00 AM</span><br/>
<span id="flightArrivalTimeToHome1" class="fontSize26">Arrive: 12.00 PM</span><br/>
</div>
</div>
</div>
<div id="flightDetailsRightPanel1" class="flightDetailsRightPanel textAlignRight marginBottom10">
<img src="images/flightIcon.png" class="marginRight10 marginTop10 width40"/><br/>
<button class="marginRight10 marginBottom10 width40 bookNowButtonStyle">Book Now</button>
</div>
</div>
</div>
Inside this div for 5 times
<div id="searchFlightResultDiv" class="fullWidth" style="border:solid">
</div>
Is there a better way to do that rather than string appending in jQuery?
Thanks,
Ankit Tanna
You'll need to wrap your template div (#flightIndex1) in a container with a unique id attribute. Then, you take the contents of that container (a template for a single record), and append it to your results div (#searchFlightResultDiv) using some type of loop based on the number of results received.
Basically,
HTML:
<!-- Here's your template -->
<div class="displayNone" id="oneWayFlightElement">
<!-- This id (singleResult) is important -->
<div id="singleResult">Result</div>
</div>
<!-- Container for the results -->
<div id="results"></div>
Javascript:
//Get the number of results.
//This can be sent from your API or however you're getting the data.
//For example, in PHP you would set this to $query->num_rows();
var count = 5;
//Start a for loop to clone the template element (div#singleResult) into div#results 'count' times.
//This will repeat until the number of records (count) has been reached.
for (i = 1; i <= count; i++) {
//Append the HTML from div#thingToRepeat into the #results.
$('#results').append($('#singleResult').clone());
}
Here's a JSFiddle to show you how it works. You can play with it and tweak it if necessary.
I can't in good conscious complete this post without telling you the downsides of this. Doing it this way is majorly frowned upon in the web development community and is super inefficient. It may be good for practice and learning, but please do take a look at and consider a javascript templating framework like moustache or handlebars. It does this same thing but way more efficiently.
Hope this was helpful!
function populateResult(resCount) {
resCount = typeof resCount === 'number' ? resCount : 0;
var res = [];
var templateEle = $('#oneWayFlightElement');
for(var i = 0; i < resCount; ++i)
res.push(templateEle.clone().removeAttr('id class')[0]);
$('#searchFlightResultDiv').html(res);
}
populateResult(5);
We use an array res to hold the DOM elements as we loop and finally sets it to the target div using html method. We don't need a JQuery object here as the html method accepts any array like object. In this way we can minimize browser reflows. Here is the JSFiddle
Related
I want to send a value from html to javascript using javascript variable.
I've created a div from javascript like this:
<body>
<div id="row" class="category-cards">
// creates from js
</div>
</body>
<script>
var d1 = document.getElementById("row");
for (let i=5; i>0; i--) {
d1.insertAdjacentHTML('beforeend',
<div class="card card-small card-category">
<div class="card-del-btn">
<button id="btnDel" onclick="deleteCategory(i)"> <b> × </b> </button>
</div>
<!-- displays the record --!>
</div>
}
function deleteCategory(index){
// takes the index and searches the mysql database for match, and deletes the record
}
</script>
Each iteration of the for loop inserts a card of a record from the database, and I wish to delete that record from the document, as well as the database, when the button is clicked.
Is there a way to associate a unique id or value to each card and send it through the onclick?
I have tried sending the value of i but it is always the last index, which in this case was 0.
There many ways to achieve what you looking for but simplest one would be to use custom html attributes and provide element that triggered event as argument to your callback.
This could be achieved like this
function handleClick(element) {
const elementData = element.getAttribute('data-my-data')
// do some stuff here with element data
}
Using your code:
d1.insertAdjacentHTML('beforeend', `
<div class="card card-small card-category">
<div class="card-del-btn">
<button data-my-data="here goes your data" onclick="handleClick(element)"> <b> × </b> </button>
</div>
</div>
`)
So I used a script that I found on Stack Overlow to swap text. It worked great initially but then I tried to use it again on the same page and I noticed an issue.
You can see the problem here: JsFiddle
The HTML
<div class="gallerycard">
<div id="textMessage"></div>
<div class="textContent">
<div class="girlname">ONE LEFT</div>
</div>
<div class="textContent">
<div class="newgirl">TWO LEFT</div>
</div>
<div class="girlimage"></div>
<div class="girlinfo">TEXT</div>
</div>
<div class="gallerycard">
<div id="textMessage"></div>
<div class="textContent">
<div class="girlname">ONE RIGHT</div>
</div>
<div class="textContent">
<div class="newgirl">TWO RIGHT</div>
</div>
<div class="girlimage"></div>
<div class="girlinfo">TEXT</div>
</div>
The Jquery
var cnt=0, texts=[];
// save the texts in an array for re-use
$(".textContent").each(function() {
texts[cnt++]=$(this).text();
});
function slide() {
if (cnt>=texts.length) cnt=0;
$('#textMessage').html(texts[cnt++]);
$('#textMessage')
.fadeIn('fast').animate({opacity: 1.0}, 800).fadeOut('fast',
function() {
return slide()
}
);
}
slide()
So, how do I keep them from merging?
You need two arrays, one for each,
give each one of the gallerycards different ids
and do it twice
var cnt=0, firstTexts=[], secondTexts=[];
// save the texts in an array for re-use
$('#firstID > .textContent').each(function() {
firstTexts[cnt++]=$(this).text();
});
cnt = 0;
// save the texts in an array for re-use
$('#secondID > .textContent').each(function() {
secondTexts[cnt++]=$(this).text();
});
and call slide twice with the relevant array and id
There are multiple problems based entirely on too much copy/paste without understanding the why.
Both target divs have the same id. You should never have two elements on the same page which share the same id. Now there is a quick and dirty way to clean this up and there is a flexible and effective way to clean this up. I went for the flexible solution and I'll explain how it works as best I can.
<div class="gallerycard" data-target="textMessageLeft">
<div id="textMessageLeft"></div>
<div class="textContent">
<div class="girlname">ONE LEFT</div>
</div>
<div class="textContent">
<div class="newgirl">TWO LEFT</div>
</div>
<div class="girlimage"></div>
<div class="girlinfo">TEXT</div>
</div>
<div class="gallerycard" data-target="textMessageRight">
<div id="textMessageRight"></div>
<div class="textContent">
<div class="girlname">ONE RIGHT</div>
</div>
<div class="textContent">
<div class="newgirl">TWO RIGHT</div>
</div>
<div class="girlimage"></div>
<div class="girlinfo">TEXT</div>
</div>
Notice I added a data-target element to the gallerycard containing the id of the div we want to place the text into. I also changed the ids on each target div to be unique. This is critical to make it all work, as is the data-target element matching those ids.
texts = {};
// save the texts in an array for re-use
$(".textContent").each(function () {
var target = $(this).parent().attr('data-target');
if (texts[target] == null) { texts[target] = []; }
texts[target].push($(this).text());
});
function slide(divId, cnt) {
if (cnt >= texts[divId].length) cnt = 0;
$('#' + divId).html(texts[divId][cnt++]);
$('#' + divId)
.fadeIn('fast').animate({
opacity: 1.0
}, 800).fadeOut('fast',
function () {
return slide(divId,cnt)
});
}
for (var t in texts)
{
slide(t, 0);
}
In the javascript I changed a lot to make this an expandable and flexible solution, rather than simply duplicating what was already there with two separate names.
First, we removed the counter and changed texts to an object ({} instead of []). From here I can use texts like a hash, which simplifies the rest of the script. The key of the hash is the value of the data-target from the container div of the message and content divs. Add as many content divs as you want under each parent and they'll all be found and associated correctly.
The texts from each textContent div are stored in an array, but we are using the push() function to eliminate the need for a counter variable - counters are fine for a single instance, but they get ugly with multiples.
I changed the slide function to accept two variables: divId and cnt. divId is how the slider knows which div to target and cnt allows the recursive call to keep a private counter which will not conflict with other instances of the slider function running simultaneously.
Finally, to again prevent duplication and allow further expansion, Instead of simply calling slide, we iterate through the hash to get the divId and call a slide instance for each divId we have. Go ahead and try expanding the number of panes or adding new textContent divs under one of the headers. It all works very smoothly now.
The fiddle is here: http://jsfiddle.net/AX4LC/4/
I have a list of notes that are being posted to a view from a model and being posted to the page
<div id="listResults"></div>
<div class="pam bgpage line" id="navResults"></div>
<script id="listTemplate" type="text/x-jquery-template">
<div class="clearfix ptl phl modalRow">
<div class="ui ui_std_${Type} activity_icon"></div>
<div class="activity">
<p class="activity_head">${SubType} ${Type}</p>
<span class="activity_detail">${CreatedDuration} by ${CreatedBy}</span><br />
<div class="activity_wrap">
{{html Note}}
</div>
</div>
</div>
</script>
<script id="navTemplate" type="text/x-jquery-template">
<div class="unit size1of5 lastUnit">
{{if TotalItemCount>0}}
<label class="dgray mlm mrs">1 - ${LastItemOnPage} of ${TotalItemCount}</label>
{{else}}No Recent Activity{{/if}}
</div>
</script>
These notes are being posted in a descending order i want to make a javascript or jquery function that would take a button onclick and flip the order to ascending. Is there a way to do taht easily? I cannot find an answer.
You could try something like this, need to add the sort value to the div containing the data you would like to sort and wrap all the articles in a container div:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<script type="text/javascript" src="jquery-1.10.1.js"></script>
</head>
<body>
<input type="button" id="test" value="sort"/>
<div id="activitycontent">
<div class="activity" data-sort="22">
<span>22</span>
</div>
<div class="activity" data-sort="11">
<span>11</span>
</div>
<div class="activity" data-sort="33">
<span>33</span>
</div>
</div>
<script type="text/javascript">
(function () {
var direction = 1;
function sortHelper(a, b) {
// this can be made faster if you pre store these values
// retuns 1,-1 or 0 to sort the array of div elements
// using the value of the attribute data-sort
vala = a.getAttribute("data-sort");
valb = b.getAttribute("data-sort");
ret = vala>valb?1:(vala<valb)?-1:0;
// multiply by direction (ascending descending)
return ret * direction;
}
$("#test").on("click", null, null, function () {
// sort opposite of previously used direction.
direction = direction * -1;
// get array of html Div elements containing the article
var divArr = Array.prototype.slice.call
($("#activitycontent div.activity"), 0);
var i = 0;
var container = document.getElementById("activitycontent");
// sort the articles based on data-sort property
divArr.sort(function (a, b) {
return sortHelper(a, b);
});
// add the div elements containing the articles in the right order
for (i = divArr.length-1;i>-1;i--){
container.appendChild(divArr[i]);
}
});
})();
</script>
</body>
</html>
Well, if you had them posted in a table rather than in divs, and the thing you were sorting on was one of the columns, the jquery tablesorter plugin would hook you right up. It's a good one to learn anyway.
Alternate option - if you have enough control over your model, you could post them twice, once in the initial order, once in reverse order. Have the reverse order version start out hidden, and then when you press the button, use jQuery's .show() and .hide() to swap which is visible.
Alternate option - if you don't have that level of control over your model, you can use jquery to iterate through the list of divs once the apge is loaded, grab the list of notes with a selector, and then use .each(), .clone() and .insertBefore() to populate your reversed list, and then use the show/hide button as before.
I hope you find this helpful.
i'm just creating a grid system for responsive web design and my code (simplified) looks like this:
<div id="row1">
<div class="type_3">
</div>
<div class="type_1">
</div>
<div class="type_2">
</div>
<div class="type_2">
</div>
</div>
Now I want to get the names of the classes and the order of the elements, that are direct children of .row1 as an array or string (or similar) in js.
The order is very important in this case.
Any ideas?
Thanks in advance,
JBG
Iterate over the children of #row1 node:
var children = document.getElementById("row1").children;
for (var i = 0; i < children.length; ++i) {
alert(children[i].className);
}
alert is just for a quick demo, do anything you want inside the loop. Here is a jsfiddle.
I am having a problem with dynamically generating this dropdown menu. This works if I'm not making it dynamically.
The #t.Id is working and is different every time in the loop. I'm pretty sure its the first line that's wrong as I have used the id="" before this way.
<b>tagged</b>
<div style="display: none;">
<div id="tagsdiv#(t.Id)">
<span class="menu">hhhh<br />
nnnn
#for( int i = 0; i < t.tTags.Count; i++ ) {
<b>#Html.ActionLink( t.tTags[i], "TagDetail", "Forums", new { tag = t.tTags[i], page = 0 }, null )</b>
}
</span>
</div>
</div>
Tips to debug Razor (or any server-side code rendering markup) more effectively:
View the rendered HTML! is it correct?
Remove styles/scripts until you are sure the server is rendering the values you want.
Add a breakpoint to your controller to make sure you are passing data to the view. Your rendering logic may be fine.
That said, your code appears to work fine. I dummied up some data:
#{ var t = new { Id = 1234, tTags = new List<string> { "foo", "bar", "baz" } }; }
<b>tagged</b>
<div style="display: none;">
<div id="tagsdiv#(t.Id)">
<span class="menu">
#for( int i = 0; i < t.tTags.Count; i++ ) {
<b>#Html.ActionLink( t.tTags[i], "TagDetail", "Forums", new { tag = t.tTags[i], page = 0 }, null )</b>
}
</span>
</div>
</div>
This yields:
<b>tagged</b>
<div style="display:none;">
<div id="tagsdiv1234">
<span class="menu">
<b>foo</b>
<b>bar</b>
<b>baz</b>
</span>
</div>
</div>
One thing that really looks wrong here is '#tagsdiv1234'. Are you sure your tooltip needs an ID including the CSS/jQuery ID selector ("#")?
Another thing that stands out is your tooltip container is wrapped with an outer div set to display:none. The ID'd element will always be hidden because its parent is hidden, even if the tooltip code tries to show it.
Another possibility is that your ID contains a character illegal in an element identifier.