I have displayed products in divs and users can click on them, to select them. The problem i have is that only one product can be selected. I wan't to change this functionality to be multi selected and function should collect id's of products.
This is my HTML for products
<div class="product_item hit w_xs_full" ng-repeat="p in products track by $index" style="float: left; background-color: blue;">
<figure class="r_corners photoframe type_2 t_align_c tr_all_hover shadow relative"
ng-click="selectUserItems($index)" ng-class="{sel: $index == selected}">
<!--product preview-->
<img ng-src="images/products/{{p.images[0].thumbName}}" alt="{{p.name}}" class="tr_all_hover">
<!--description and price of product-->
<figcaption>
<br>
<h5 class="m_bottom_10"><b>{{p.name}}</b></h5>
<p class="scheme_color f_size_large m_bottom_15" style="color:black;">Located in: <b>{{p.country}}</b></p>
<a href="#/swap/{{p.mainCategorieLink}}/{{p.subCategoryLink}}/{{p.alias}}">
<button class="button_type_4 bg_scheme_color r_corners tr_all_hover color_light mw_0 m_bottom_15">See item</button>
</a>
</figcaption>
</figure>
</div>
And this is my controller function for selecting items
//select items
$scope.selectUserItems = function(index){
$scope.selected = index;
};
Once item is selected background of div is colored blue
.sel {
background-color:#5ACBFF;
}
So how to properly write controller function so you can select multiple divs and $scope.selectd variable collects ids of products.
Currently, $scope.selected = index; holds only one index, you either need to make it an array and toggle the current selection:
Variant 1
$scope.selected[index] = !$scope.selected[index];
and change your ngClass definition:
ng-class="{sel: $index[selected]}"
Variant 2
or change your ngClick-function:
ng-click="selectUserItems(p)"
And the selectUserItems function
$scope.selectUserItems = function(item){
item.selected = !item.selected;
};
and change your ngClass definition:
ng-class="{sel: p.selected}"
In the product object, add a field 'selected' to control whether the item is selected. And toggle the value of selected in ng-click:
<figure class="...." ng-init="p.isSelected = false"
ng-click="p.isSelected = !p.isSelected" ng-class="{sel: p.isSelected}">
Related
I have a page that includes a section that's generated from a csv file (in Jekyll, using liquid). In this section, I have individual divs with an image and description. I need to find each div that fits a specific description.
<div class="row">
{% for item in site.data.items %}
<div class="col-md-3 item {{ item.test }} {{ item.industry }} {{ item.shape }}">
<img src="source here">
<br/>
<p>{{ item.name }}</p>
<p>{{ item.description }}</p>
</div>
{% endfor %}
</div>
I assigned classes to each div, and pulled the classes from the csv. This generates a class name of something like "item sticky food pasta".
Now I want to filter the displayed items when a user selects options on the page. I created an array, selectedOptions:
var selectedOptions = [];
Hide the other items:
$(".item").hide();
Push the selected options to the array:
$('input[name="filter-input"]:checked').each(function(i){
selectedOptions.push($(this).val());
});
And loop through the options to display only the items that have the classes selected:
for (var i = 0; i < selectedOptions.length; i++) {
$('.item').each(function() {
if ($(this).hasClass(selectedOptions[i])){
$(this).show();;
}
});
}
This works great, if I wanted every item that has any of the classes. However, what I want is a cumulative effect: I want only the items that have BOTH food AND pasta as a class.
How can I show every item that has all the classes? I know I can use something like $('.classa.classb'), but I'm not sure how to use that with the array I have here.
Thank you!
You can use querySelectorAll to do the dirty work for you in finding all the elmeents that match. Just build up a selector string.
const wrapper = document.querySelector(".wrapper");
document.querySelector("fieldset").addEventListener("change", function () {
const cbs = Array.from(document.querySelectorAll('input[type="checkbox"]:checked'));
const selectedClasses = cbs.map(cb => cb.value).join("");
const matchedElems = wrapper.querySelectorAll(selectedClasses);
console.log(matchedElems);
});
<div class="wrapper">
<div class="one">1</div>
<div class="two">2</div>
<div class="three">3</div>
<div class="one two">1 2</div>
<div class="one three">2 3</div>
<div class="two three">1 3</div>
<div class="one two three">1 2 3</div>
</div>
<form>
<fieldset>
<legend>Filters</legend>
<input type="checkbox" value=".one" id="cb1" /><label for="cb1">1</label>
<input type="checkbox" value=".two" id="cb2" /><label for="cb2">2</label>
<input type="checkbox" value=".three" id="cb3" /><label for="cb3">3</label>
</fieldset>
</form>
Consider the following.
$(".item").hide();
$('input[name="filter-input"]:checked').each(function(i){
$(".row > .item." + $(this).val()).show();
});
This will hide all items and then iterate each of the selected. It will show each of the elements that has the Class selected. The Selector does all the work.
E.G. If the user selects food and pasta, all the row that have food and pasta as a child will be shown.
$(".row > .item.pasta").show();
This will be done for each checked item.
You can also bank them up in an Array as you suggested. E.G.:
selectedOptions = ["food", "pasta"];
You can simply use .join(), yet you may want to add . to each so it can be a Class selector.
$(".item").hide();
var selectedOptions = [];
$('input[name="filter-input"]:checked').each(function(i){
selectedOptions.push($(this).val());
});
$.each(selectedOptions, function(k, v){
selectedOptions[k] = "." + v;
});
$(selectedOptions.join(", ")).show();
This will result in something like:
$(".food, .pasta").show();
You might notice how this is a lot of extra code to accomplish the same thing.
Hi currently i am developing an filtering application . Please see my html and js code
jQuery(document).ready(function($){
$(".color-label").on("click",function(){
var color_box_val= $(this).find('.color-box').val();
$('.test-li').hide();
$('div:contains('+color_box_val+')').closest('.test-li').show();
});
});
.hidden-color{
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<label class="color-label">Red<input type="checkbox" class="color-box" value="red"/></label>
<label class="color-label">Black <input type="checkbox" class="color-box" value="Black"/></label>
<ul>
<li class="test-li">
<div class="test-div">
<p class="hidden-color">red</p>
red poduct
</div>
</li>
<li class="test-li">
<div class="test-div">
<p class="hidden-color">Black</p>
black Product
</div>
</li>
<li class="test-li">
<div class="test-div">
<p class="hidden-color">Blue</p>
blue Product
</div>
</li>
So here what iam doing is when customer click black , then it will show black product . If the customer click both red and black then we need to show both , and if customer didn't tick anything then we need to show all product .
But i stuck in some point . Here how can i show both red and black when the clicked both ? Currently it is showing the result based on newly clicked check box . Also if they untick every thing then i need to show all box . Please suggest .
The first thing I would recommend changing is how you store color data in your list items. Instead of storing them in a hidden paragraph element, why not store them as HTML5 data- attributes?
Once that is done, it is quite simple to do what you intend: which is basically a OR operation, i.e. when red and black are ticked, you want to show items that are red or black.
The logic is as follow:
You listen to the .change() event on all the checkboxes
When this event is fired, you want to collect the values of all these checkboxes, but only if they are checked. This is done by using .filter(':checked') to select for checked checkboxes and .map() to return the array.
Next, you iterate through all the list items. If their data-color values are found in the array, you show them. Otherwise you hide them.
And all this logic is wrapped within a conditional statement that checks if any of the checkboxes are filtered:
If none is checked, we do not want any filtering
If one or more is checked, we perform filtering using the aforementioned filtering logic
Update: I have used .toLowerCase() to convert all your color values to lowercase, since from your question I can see that the values might be optionally capitalised.
See proof-of-concept example below:
jQuery(document).ready(function($) {
// Listen to change event
$('.color-box').change(function() {
// Store checked checkboxes
var $checked = $('.color-box').filter(':checked');
if ($checked.length) {
// Perform filtering if one or more is checked
// Collect ALL values from all .color-box into an array
var colors = $checked.map(function() {
return $(this).val().toLowerCase();
}).get();
// Iterate through each list item and evaluate
$('.test-li').each(function() {
var $t = $(this);
if (colors.indexOf($t.data('color').toLowerCase()) >= 0) {
$t.show();
} else {
$t.hide();
}
});
}
// If nothing is checked, show all list items
else {
$('.test-li').show();
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<label class="color-label">Red<input type="checkbox" class="color-box" value="red"/></label>
<label class="color-label">Black <input type="checkbox" class="color-box" value="Black"/></label>
<ul>
<li class="test-li" data-color="red">
<div class="test-div">
red Product
</div>
</li>
<li class="test-li" data-color="black">
<div class="test-div">
black Product
</div>
</li>
<li class="test-li" data-color="blue">
<div class="test-div">
blue Product
</div>
</li>
I am working on asp.net mvc and I have partial view where products are displayed using a foreach loop on product views.
My requirement is little bit different : if there are more than 4 products, then the display must change. For the moment, each product is shown differently, how can I do this ?
Just like below image each product show differently :
Here is my current code :
#foreach (var item in Model)
{
<div class="item-box">
<div class="category-item">
<h2class="title">
#item.Name
</h2>
<div class="picture">
<a href="#Url.RouteUrl("Category", new { SeName = item.SeName })" title="#item.PictureModel.Title">
<img alt="#item.PictureModel.AlternateText"src="#item.PictureModel.ImageUrl" title="#item.PictureModel.Title" />
</a>
</div>
</div>
</div>
}
Below is part of some code on an html page that lists shopping cart products. Using JavaScript/jQuery, I need to be able to loop through the li items and get the div "data-" values for each. The issue that I am having is that there are no IDs for the div that has the data- value (). I only see the div for "CategoryContent".
<div class="Block CategoryContent Moveable Panel" id="CategoryContent">
<ul class="ProductList ">
<li class="Odd">
<div class="ProductImage QuickView" data-product="577">
<img src="http://cdn3.example.com/products/577/images/1731/2311-.jpg?c=2" alt="Sweater Vest V-Neck Cotton" />
</div>
<div class="ProductDetails">
Sweater Vest V-Neck Cotton
</div>
<em class="p-price">$45.04</em>
<div class="ProductPriceRating">
<span class="Rating Rating0">
<img src="http://cdn3.example.com/templates/custom/images/IcoRating0.png?t=" alt="" style="" />
</span>
</div>
<div class="ProductActionAdd" style="display:;">
Choose Options
</div>
</li>
</ul>
</form>
</div>
So, there is only one li item here, on a typical page, there are up to 9. My goal is to use JavaScript to get the data-product values and then use that to look up a better image thumbnail and have it replaced. So, how do I get the value set for data-product?
Quite easy:
// Loop through all list items of ul.ProductList:
$("ul.ProductList li").each(function (index, element) {
// Find the element with attribute data-product:
$dp = $(element).find("[data-product]");
// Get the value of attribute data-product:
var product = $dp.attr("data-product");
// Now set the high quality thumbnail url:
var url = "/images/hq/" + product + ".png"; // Note that this is just an example
// Here you can use $(element) to access to current li (and the img):
$(element).find('.ProductImage img').attr('src', url);
});
You can use this:
$("#CategoryContent div[data-product]").each(function(){
alert($(this).attr('data-product'));
});
Pure JS:
var divs = document.querySelectorAll('#CategoryContent div[data-product]');
var index = 0, length = divs.length, prodIds = [];
for ( ; index < length; index++) {
prodIds.push(divs[index].getAttribute('data-product'));
}
Fiddle: http://jsfiddle.net/we5q7omg/
You could use the class name to get the data-product
var products = document.getElementsByClassName("ProductImage");
for(var i=0; i<products.length;i++)
{
console.log(products[i].getAttribute("data-product"));
}
Using JQuery, you can get the elements with the data-product attribute by simply calling
$('[data-product]')
// Or if you only want the data-product elements within the UL.
$('ul').find('[data-product]')
From there you can simply do pull the products from the elements. For Example:
var products = $('[data-product]').map(function() {
return $(this).data('product');
});
I have a ng-repeat which display a list of divs and when I click on one it shows an aditionnal div for the clicked item.
This is working
<div ng-repeat="item in items">
<div ng-click="showfull = !showfull">
<div>
<h1>{{item.title}}</h1>
<p>{{item.content}}</p>
</div>
</div>
<div ng-show="showfull">
<p>{{item.info}}</p>
</div>
<hr/>
</div>
My items are loaded from a json containing a list of item and each item have a default attribut showfull set to false in this json. This is working, but now I want to hide all others item in the list when an item is clicked. I've tryied something like this :
This is not working
<div ng-repeat="item in items">
<div ng-click="expand(item)">
<div>
<h1>{{item.title}}</h1>
<p>{{item.content}}</p>
</div>
</div>
<div ng-show="showfull">
<p>{{item.info}}</p>
</div>
<hr/>
</div>
and in the controller I've added a function :
$scope.expand = function(e) {
e.showfull = !e.showfull;
//TODO: put here a foreach logic to hide all other items
}
But even without the foreach logic this is not working, the item don't show the additionnal div when clicked. I have two question :
I suppose this is due to item being "passed by copy" in the expand function or some kind of scope isolation issue but can you explain me why in detail ?
SOLVED
How can I hide all the additional div of other items when I click an item and show the additionnal content for this item ? Do I need to do a directive ?
NOT SOLVED
Thanks
I think you're on the right track. You need to set the showfull on the item and then use ng-show or ng-if to hide it, or as Gavin mentioned, use a class.
On ng-click you can call your expand function, where you pass the item, toggle it and set all others to hidden.
Template:
<div ng-repeat="item in items>
<div ng-click="expand(item)">
<div>
<h1>{{item.title}}</h1>
<p>{{item.content}}</p>
</div>
</div>
<div ng-show="item.showfull">
<p>{{item.info}}</p>
</div>
<hr/>
</div>
Controller:
$scope.expand = function (item) {
angular.forEach($scope.items, function (currentItem) {
currentItem.showfull = currentItem === item && !currentItem.showfull;
});
};
Your expand method is modifying the item, so your ng-show needs to reference the item:
<div ng-show="item.showfull">
<p>{{item.info}}</p>
</div>
To hide all of your items you need to do something like
$scope.expand = function(item) {
angular.forEach(items, function(i) {
if (i === item) {
i.showfull = !i.showfull;
} else {
i.showfull = false;
}
});
};
Shouldn't the second div you want to show be referencing the item?
<div ng-repeat="item in items>
<div ng-click="expand(item)">
<div>
<h1>{{item.title}}</h1>
<p>{{item.content}}</p>
</div>
</div>
<!-- Added item to ng-show -->
<div ng-show="item.showfull">
<p>{{item.info}}</p>
</div>
<hr/>
</div>