I want to add "product compare feature" in my website product list. I am wondering how can I make a Query String URL from product list page using jQuery. Looks like below one.
I need compare URL should be generated like below, and maximum product can be added as 4.
Compare Products
Fiddle: http://jsfiddle.net/taxjD/341/
I can handle these query string parameter on compare.html page.
<div id="container" class="hidden">
<p>There are 0 boxes</p>
**Compare**
</div>
<div>
<div>
<h1>Product Name 1</h1>
+ Add to compare
<span class="ProdId">123</span>
</div>
<div>
<h1>Product Name 2</h1>
+ Add to compare
<span class="ProdId">124</span>
</div>
<div>
<h1>Product Name 3</h1>
+ Add to compare
<span class="ProdId">125</span>
</div>
</div>
Jquery
$(".more").click(function() {
var id=$(this).next('.ProdId').html();
$("#container").append("<div class='box'> "+ id + "<a href='#'>x</a></div>");
var count = $(".box").length;
$("p").text("There are " + count + " boxes.");
$("#container").removeClass("hidden");
});
$(".box a").live("click", function() {
$(this).parent().remove();
var count = $(".box").length;
$("p").text("There are " + count + " boxes.");
});
You need to somehow keep track of the items that have been selected. That could be an array variable that you updated both on add and remove, but it could also be indicated in the .box elements you're creating. If you wrap the product ID in a span in the .box elements as well, you'll have an easier time targeting the ID:
$('<div/>', { 'class': 'box' })
.append($('<span/>', { class: 'prod-id', text: id }))
.append($('<a/>', { href: '#', text: 'x' }))
.appendTo('#container');
You could then do:
var ids = $('.box .prod-id')
.map(function(i, x) { return ['P', ++i, '=', $(this).text()].join(''); })
.toArray();
$('#container > a').attr('href', 'Compare.html?' + ids.join('&'));
Demo
Update:
Your additional requests are easily fulfilled now that we've established a way of retreiving the added products' IDs. Since we'll be reusing it, I've extracted getSelectedIds as a function of its own.
Now we just need to check its length to test the max 4 requirement, and its indexOf(id) to test whether the item was already added. If so, the code will just exit the .more click listener. You could show the user an error message at that point.
Updated demo
Related
Would just like to get and set different attributes when a list item is moved to the other list on my mvc page... I can't access anything so far. The problem is in the javascript, it hits the onchange event fine. I didnt post the "available list" in the cshtml for brevity. this is what the console.log as the bottom reads:
SpecialNeedInActiveList change: Meds per tube newIndex: -1 oldIndex: 5 action: remove
SpecialNeedActiveList change: Meds per tube newIndex: 3 oldIndex: -1 action: receive
Any help would be appreciated, this has taken way too long for me.
HTML:
<div class="col-md-6" id="SpecialNeedContainerLL">
<ul id="SpecialNeedActiveList" class="col-md-6">
#if (Model.SelectedSpecialNeeds.Any())
{
foreach (var y in Model.SelectedSpecialNeeds)
{
<li class="list-item" selected-personspecialneed="#y.PersonSpecialNeedId" selected-need-type="#y.SpecialNeedTypeId"> #y.SpecialNeedDescription </li>
}
}
</ul>
</div>
#(Html.Kendo().Sortable()
.For("#SpecialNeedActiveList")
.ConnectWith("#SpecialNeedInActiveList")
.PlaceholderHandler("placeholder")
.Events(events => events.Change("onChange"))
)
Javascript:
function onChange(e) {
var id = e.sender.element.attr("id"),
text = e.item.text(),
newIndex = e.newIndex,
oldIndex = e.oldIndex;
if (id == 'SpecialNeedActiveList' && newIndex > -1) {
//add item to selected list
//remove item from availables list
/*NONE of the following works...*/
//var oldPersonSpecialNeedId = e.sender.element.getAttribute('available-personspecialneed');
//var oldSpecialNeedTypeId = e.sender.element.getAttribute('available-need-type');
//e.sender.element.removeAttribute('available-personspecialneed');
//e.sender.element.removeAttribute('available-need-type');
//e.sender.element.setAttribute('selected-personspecialneed', oldPersonSpecialNeedId);
//e.sender.element.setAttribute('selected-need-type', oldSpecialNeedTypeId);
}
console.log(id + " change: " + text + " newIndex: " + newIndex + " oldIndex: " + oldIndex + " action: " + e.action);
}
When you are in the change event handler(onChange()), e.sender.element is NOT the item that was dragged, it is the list that sent the change event, the <ul> element.
The item being drag/dropped is contained in the e.item field, which you should be able to manipulate as normal, for example using jQuery(but you may use whatever DOM manipulation technique you like):
var $item = $(e.item);
var oldPersonSpecialNeedId = $item.attr('selected-personspecialneed');
var oldSpecialNeedTypeId = $item.attr('selected-need-type');
$item.attr("selected-personspecialneed", "new" + oldPersonSpecialNeedId);
$item.attr("selected-need-type", "new" + oldSpecialNeedTypeId);
Here's a working example showing the attributes being changed:http://dojo.telerik.com/#Stephen/arUpO
It is based on single list from the code in your question rather than 2 lists but it simply demonstrates how to access the dragged element from the sortable change event, which is the core of your problem.
Having said that, I would probably investigate using a DataSource-bound list so that you can manipulate fields of a model instead of attributes of a DOM element. http://demos.telerik.com/aspnet-mvc/sortable/integration-listview is a good place to start.
I have a page with a very large table (several thousand rows).
The table shows a subset of data specified by certain filters. I need the table to update whenever one of the filters changes.
Basically, there are a few check boxes and a text box, whenever one of these changes I reload the table to display only those rows which fit the criteria specified by the user.
I'm doing this by clearing the table and reloading the rows that match the filters. This works but has proven to be very slow.
Here is my javascript code:
function reloadTable() {
var tablebody = document.getElementById("tablebody");
while(tablebody.hasChildNodes()) tablebody.removeChild(tablebody.firstChild);
filter = new FilterChecker();
for (var i=0;i<rows.length;i++) {
if (filter.isVisible(rows[i]))
addRowToTable(rows[i]);
}
}
Is there a way to make it faster?
Alright, sorry for the delay, but I got wrapped up in work. I came up with a nice set of logic that illustrates what you need.
FIDDLE
I created some simple html to illustrate the point. It contains two drop downs to mimic the filters and 8 data rows to mimic your data grid.
<div id="body">
<select id="filterA" class="filter" name="states">
<option value="filterACT">Connecticut</option>
<option value = "filterAMA">Mass</option>
</select>
<select id="filterB" class="filter" name="towns">
<option value="filterBBT">Big Town</option>
<option value = "filterBST">Small Town</option>
</select>
<div id="grid">
<div class="row filterACT filterBBT">BigTown CT 1</div>
<div class="row filterACT filterBBT">BigTown CT 2</div>
<div class="row filterACT filterBST">SmallTown CT 1</div>
<div class="row filterACT filterBST">SmallTown CT 2</div>
<div class="row filterAMA filterBBT">BigTown MA 1</div>
<div class="row filterAMA filterBBT">BigTown MA 2</div>
<div class="row filterAMA filterBST">SmallTown MA 1</div>
<div class="row filterAMA filterBST">SmallTown MA 2</div>
</div>
</div>
</br>
<hr/>
<div>LOG</div>
<hr/>
<div id="log"></div>
The log div is simply to show an output, which I think would be helpful. Each row is identified by class 'row' followed by another series of classes. These classes help determine what their filter data is. You would need to set this programmatically when building the grid. Additionally, these class names must match the filter option values. You can see that the first row has classes from the first option in filterA and from the first option in filterB.
Now, the javascript is a bit verbose, but you can refactor to your hearts content. Sometimes I find it easier when things are explicit when you are trying to understand them. Also, admittedly, I would do this with jQuery, so my pure Javascript isn't as sharp.
var elements = document.getElementsByClassName('filter');
writeToLog("Filter elements found: " + elements.length);
for(var e = 0;e < elements.length;e++)
{
elements[e].onchange =function() {
writeToLog('Filter event fired for id:'+this.id);
filterChange();
};
}
First I get all the elements with the filter class, this would be your filters. I then iterate over them and set their onchange event to call the filterChange() method. The writeToLog() method calls are just for output purposes.
function filterChange() {
var filterClasses = [];
for(var i = 0;i<elements.length;i++) {
writeToLog('Pushing ('+elements[i].value+') into filter class variable.');
filterClasses.push(elements[i].value);
}
In the first part of the function I get all the select filter option values and put them into an array.
writeToLog('Filter classes: ' + filterClasses);
var rows = document.getElementsByClassName('row')
writeToLog('Row count: ' + rows.length);
I then get all of the rows, in my grid and start to iterate over them:
for(var j = 0;j<rows.length;j++)
{
writeToLog('Checking row: ' + rows[j].className);
var rowIsHidden = false;
Once I have a row, in the loop, I iterate the filter classes in the array and see if this row's classes have it. If not, I set rowIsHidden to true, otherwise it stays false.
for(var k = 0;k<filterClasses.length;k++)
{
writeToLog('Checking for class: ' + filterClasses[k]);
if(rows[j].className.indexOf(filterClasses[k]) < 0)
{
writeToLog('Class not found, hide this row.');
rowIsHidden = true;
break;
}
}
Before the loop moves to the next row, I set the display style based on the rowIsHidden value.
writeToLog('Row is hidden: ' + rowIsHidden);
rows[j].style.display = rowIsHidden ? 'none' : 'block';
}
}
By all means, this can be cleaned up and certainly optimized, but I think the intent and logic is fairly clear. Hope this helps and feel free to question any of it :)
I have the following JQuery code:
var test = new Array();
$(".quiz_list_row").each(function(index){
// Gets the data necessary to show game chosen
$quiz_list_id = $(this).data("quizlistId");
$quiz_level_reached = $(this).data("quizlevelReached");
test.push($quiz_list_id,$quiz_level_reached);
$(this).click(function(){
alert("test: "+test);
});
});
The divs (using html5 to send data):
<div class="quiz_list_row" data-quizlist-id="1" data-quizlevel-reached="5">
<div class="inline quiz_list_cell" id="quiz_list_cell_row0_id1">Quiz 1</div>
<div class="inline quiz_list_cell" id="quiz_list_cell_row0_id2">Current level: 5</div>
</div>
<div class="quiz_list_row" data-quizlist-id="2" data-quizlevel-reached="7">
<div class="inline quiz_list_cell" id="quiz_list_cell_row1_id1">Quiz 2</div>
<div class="inline quiz_list_cell" id="quiz_list_cell_row1_id2">Current level: 7</div>
</div>
The problem is that I need to find out how to use the data in the array test when the user clicks on a specific row (I want to use $quiz_list_id and $quiz_level_reached).
Unless there is a specific reason you're extracting the attributes and putting them into an array, I think you're taking some unecessary steps to achieving what you want. Take away the complexity from this, you have access to the data attributes with the .data() method at any time you have access to the elements jQuery object, one of those times is within the click handler itself.
var quizRows = $(".quiz_list_row");
quizRows.click(function(event) {
var self = $(this);
//As the element clicked on has it's data attributes defined
//You would just need to retrieve it when the element is clicked on
var id = self.data('quizlist-id'),
level = self.data('quizlevel-reached');
console.log("id is " + id);
console.log("level is " + level);
}
I am trying to build a function for inserting the number of Facebook Likes into a Div tag. So far, I have a script that can get the URL from a Div tag which is inside of another Div tag called 'entry' and then have the .getJSON() method retrieve the number of Facebook likes for each entry.However, I can't get each retrieved value of Facebook Likes to insert into a Div tag for each entry. Please note, I simplified my code to where it alerts each Facebook Like value. This is what I have so far:
<div class="entry">
<div class="fburl">https://graph.facebook.com/zombies</div>
<div class="facebook-likes"></div>
</div>
<div class="entry">
<div class="fburl">https://graph.facebook.com/starwars</div>
<div class="facebook-likes"></div>
</div>
And here's my jQuery:
$(document).ready(function(){
$(".entry").each(function() {
var fbURL = $(this).find(".fburl").html();
$.getJSON(fbURL, function(fbData) {
var fbArr = fbData['likes'];
alert(fbArr);
});
});
});
​So what I am trying to do is iterate through each entry, get the Open Graph URL for it, retrieve the Likes value, and then insert it into the appropriate Div tag, so the code should render as:
<div class="entry">
<div class="fburl">https://graph.facebook.com/zombies</div>
<div class="facebook-likes">2,586 Likes</div>
</div>
<div class="entry">
<div class="fburl">https://graph.facebook.com/starwars</div>
<div class="facebook-likes">8,905,721 Likes</div>
</div>
​
​
$(document).ready(function() {
$('.entry').each(function() {
var $this = $(this),
fbURL = $this.children('.fburl').html();
$.getJSON(fbURL, function(fbData) {
$this.children('.facebook-likes').html(fbData['likes'] + ' Likes')
});
});
});
See: http://api.jquery.com/children
Demo: http://jsfiddle.net/9EALz/2/
Note: Using children() is going to be marginally more efficient than using find() as it limits the DOM traversal to a single level ( http://jsperf.com/find-vs-children/13 ). Cashing the jQuery object $(this) via var $this = $(this) is also slightly more efficient as it prevents unnecessary selector interpretation ( http://jsperf.com/jquery-cache-vs-no-chace ).
You may want this
$(document).ready(function(){
$(".entry").each(function() {
var entry=$(this), fbURL=$(".fburl", entry).html(),
el=$('.facebook-likes', entry);
$.getJSON(fbURL, function(fbData) {
el.html(numberWithCommas(fbData['likes'])+" Likes");
});
});
});​
A thousand separator function from here
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
DEMO.
Update:
Alternatively you can use this too (using data-attribute) without an extra div for fburl, i.e.
<div class="entry">
<div data-fburl="https://graph.facebook.com/zombies" class="facebook-likes"></div>
</div>
JS
$(".entry").each(function() {
var entry=$(this), fbURL = $(".facebook-likes", entry).attr('data-fburl'),
el=$('.facebook-likes', entry);
$.getJSON(fbURL, function(fbData) {
el.html(numberWithCommas(fbData['likes'])+" Likes");
});
});
I was wondering how I would go about finding and replacing some text in a div, but i want to find and replace the second occurrence of that text. For example:"You just added a item, please remove this item" so I would like to find the second "item" and replace it with whatever text I choose.
JS:
var compareCount = $('.compareWidget').find('.compareItem').length;
if (compareCount >= 2) {
$('.message').find('.count').text(compareCount);
$('message').html().replace('item', 'items');
}
$('.message').slideDown("Fast");
setTimeout(function () {
$('.message').slideUp("Fast");
}, 5000);
HTML:
<div id="alertMessage">
<div class="message">
<span>You just added a item to compare, you currently have <span class="count">1</span> item to compare</span>
</div>
</div>
"you currently have 1 item to compare"
You want to turn item to items?
You can do it with regular expressions, or you can wrap it into an element and grab that.
<span class="count">1</span> <span class="type">item</span> to compare</span>
and
$('.message').find('.type').text("items");
Using regular expressions you can
function replaceMatch(originalString, searchFor , replaceWith, matchNumber)
{
var match = 0;
return originalString.replace(searchFor, function(found){
match++;
return (match===matchNumber)?replaceWith:found;
},'g');
}
and call it like
var msg = $('.message');
msg.html( replaceMatch( msg.html(), 'item', 'items', 2) );
demo http://jsfiddle.net/gaby/crhvA/