I'm using an input field to accept comma-separated values then dynamically generating list items for each comma-separated value. However, I don't want items added to the list until they have a comma after them. For example, if I enter "Dog, Cat, Fish" in the input field, I don't want the following as I'm typing "Cat"
Dog
Ca
I want "Cat" to be added only once I've put a comma after it to indicate it is a complete entry.
Here's the code I'm using to achieve this.
<input ng-list ng-model="labels" placeholder="Enter labels">
<div>
<ul>
<li ng-repeat="label in labels track by $index">
{{ label }}
</li>
</ul>
</div>
Link to running example
What's the angular way to achieve this?
One way to do this would be to use custom filters to filter the ng-repeat items instead of relying on the ng-list directive.
See the associated PLUNKER of the code below.
HTML
<input ng-model="labels" placeholder="Enter labels" />
<div>
<ul>
<li ng-repeat="label in labels | completeList">
{{ label }}
</li>
</ul>
</div>
JAVASCRIPT
filter('completeList', function() {
return function(items) {
var list = [];
if(items) {
list = items.split(',');
var last = list[list.length - 1];
if(items.charAt(items.length - 1) != ',' || last.length === 0)
list.pop();
}
return list;
};
});
Related
I'm currently working with a website using PHP and AngularJS, I have a product list and a droplist that has some links which will allow the user to filter products by type(electric guitars, acoustic guitars, etc...) is there any way to do a function that filters the ng-repeat to only show products whose type are the selected one?
This is what I currently have:
<article class="producto" ng-repeat="product in dbproducts | filter:prodsearch">
<div class="img">
<img src="products/img/{{product.Imagen}}" alt="{{product.Marca + ' ' + product.Modelo}}">
<p class="product-model">{{product.Marca + ' ' + product.Modelo}}</p>
<span class="product-price">{{product.Precio | currency: '€'}}</span>
</div>
<div class="check">
<div class="paygroup">
<p class="price" ng-bind="product.Precio | currency: '€'"></p>
<button class="buy"><i class="fa fa-shopping-cart"></i>{{'BUTTON_BUY' | translate}}</button>
<p>{{'BUTTON_AVAILABLE' |translate}}: {{product.Unidades_disponibles}} </p>
</div>
</div>
<div class="txt">
<p>Test, hola, {{ $index }}</p>
</div>
<span class="close fa fa-times fa-inverse"></span>
</article>
So If I get your code right, you already have a pipe filter in your ng-repeat:
| filter:prodsearch
So I guess somewhere in an input directly or in your controller you hare binding a user input to the variable "prodsearch" and the ng-repeat is live filtered.
In the same way, you can have buttons, whether they are in a droplist or not, which click action would be assigning a certain text to the "prodsearch" variable.
A filter is what you want. Another way is Using a copy array of products to show and writing a function which update your array of products. This function receives a type and just add related products to showing items.
Something like this:
Controller
Call this function on ng-change of drop down
$scope.filters = ["all", "electric", "guitars", "acoustic", "guitars"];
$scope.selectedFilter = "all";
$scope.filterProds() {
if ($scope.selectedFilter == "all") {
$scope.dbproductsToShow = $scope.dbproducts;
} else {
$scope.dbproductsToShow = [];
$scope.dbproducts.forEach(function(itm) {
if (itm['type'] == filter) {
$scope.dbproductsToShow.push(itm);
}
});
}
}
And in your Html
<select ng-model="selectedFilter" ng-options="filter in filters" ng-change="filterProds()"></select>
<article class="producto" ng-repeat="product in dbproductsToShow">
I've fixed it, what I did was:
Adding another pipe in ng-repeat called filter: producttype
Added a $scope.producttypevariable;
Changed the value of the variable each time I clicked on the links in the dropdown so it would filter by type. This:
<li ng-click="producttype='electrica'"><a>Guitarras eléctricas</a></li>
Thanks for your help and tips, and sorry if this method is not the best, I learnt angularjs by myself(i'm not a good self-learner).
I have an ng-repeat being created like so:
<div class="items">
<!-- WANT TO HIDE THIS ENTIRE AREA IF THERE IS NO VALID ITEMS -->
<b>Items</b>
<span ng-repeat="item in items | orderBy:'priority'" itemid="{{item.$id}}" ng-if="!item.groupID || item.groupID == 'misc'">
{{item.title}}
</span>
</div>
As you can see I have an ng-if which checks if the item has a null item.groupid or is in the misc category.
Many times there is no items that match all of these criteria and in that case I want to hide the outer div <div class="items">
I can't figure out how to hide it because I can't do an ng-show on the inner elements part of the loop.
You can use a filter, and assign the result of the filter to a variable. Use that variable to decide if the enclosing div should be shown or not.
Here's a plunkr showing how it works:
<div ng-show="filteredItems.length > 0">
Test
<div ng-repeat="item in items | filter:hasGroupFilter(group) as filteredItems">
{{ item.name }} - {{ item.group }}
</div>
</div>
And in the controller:
$scope.hasGroupFilter = function(group) {
return function(item) {
return !item.group || item.group === group;
};
};
I think the cleanest way to do that is to pre filter the list, and add a condition on your parent div.items instead of using ng-if in each one of the span in the ng-repeat.
Here is a working plunker
You should filter the list in your controller and just add the condition on the parent div
<div class="items" ng-if="filteredItems.length">
<b>Items</b>
<span ng-repeat="item in filteredItems | orderBy:'priority'" itemid="{{item.$id}}">
{{item.title}}
</span>
</div>
You could potentially create a function that has access to a public variable on the outer scope. It would look something along the lines of this:
Inside your JS file
$scope.NoValidItems = true; //assume no valid items code also might look different based on how you format your angular
$scope.CheckItems = function(item){
var check = false;
if(item.groupID && item.groupID !== 'misc'){
check = true;
$scope.NoValidItems = false;
}else
check = false;
return check;
};
HTML
<div class="items" ng-if="!NoValidItems ">
<!-- WANT TO HIDE THIS ENTIRE AREA IF THERE IS NO VALID ITEMS -->
<b>Items</b>
<span ng-repeat="item in items | orderBy:'priority'" itemid="{{item.$id}}" ng-if="!CheckItems(item)">
{{item.title}}
</span>
</div>
This should work, and the if statement might not be exact, but you get the drift. Pretty much if there is one that is valid it will show, but if there is not a valid item do not show. Valid being meeting your conditional criteria. Hopefully this helps, and I explained it alright
I'm trying to create some functionality where the user would have an input box and all the data (li's) below are hidden.
Then when a user types into the input box, those li's that match that text are show.
What would the best way to do this using angular? I've set up plunker below:
http://plnkr.co/edit/T6JOBJE4LrAtshbmaoPk?p=preview
I was thinking of setting the li's to:
li {
display: none;
}
and then was going to try an ng-if with the ng-model as the value. Something like this:
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">Search</span>
<input type="text" class="form-control" ng-model="search">
</div>
<ul>
<li ng-repeat="x in data | filter:search " ng-if="!search">{{x.name}}</li>
</ul>
Can someone help point me in the right direction? Even if its just explaining the logic.
You can just set ng-show attribute to your <ul> tag, where you will watch on length of search variable and if it's greater that zero, your list with filtered results will be shown. So, you don't need any css.
<ul ng-show="search.length">
<li ng-repeat="x in data | filter:search ">{{x.name}}</li>
</ul>
Demo on plunker.
Part of your problem is the filter matches on the empty search string. You could create a custom filter to handle this, something like this http://plnkr.co/edit/i4lsuVUmOLO3pbISu7FR?p=preview
$scope.filterName = function(datum) {
console.log($scope.search, datum);
return $scope.search !== '' && datum.name.indexOf($scope.search) !== -1;
};
Used in the template like:
<ul>
<li ng-repeat="x in data | filter:filterName">{{x.name}}</li>
</ul>
Then you would have greater control over the filter if you want to tweak it in future.
I'm getting the following error while typing into the field filtered by 'completeList'. Why is this happening?
JavaScript
angular.module('myApp', ['timer'])
.controller('AppCtrl',['$scope', function($scope){
$scope.gameOn = true;
$scope.leaders = true;
$scope.myScore = true;
}])
.filter('completeList', function() {
return function(items) {
var list = [];
if(items) {
list = items.split(',');
var last = list[list.length - 1];
if(items.charAt(items.length - 1) != ',' || last.length === 0)
list.pop();
}
return list;
};
});
HTML
<div ng-show="gameOn" ng-controller="LabelCtrl" class="row marketing">
<div class="col-lg-4">
<h4>Enter comma-separated labels for this image</h4>
<form role="form" class="form-inline" >
<input ng-list ng-model="labels" placeholder="Enter labels" class="form-control" type="text" >
<button class="form-control" class="btn btn-xs btn-success">Submit</button>
</form>
</div>
<div class="col-lg-2">
<h4>Labels</h4>
<div>
<ol>
<li ng-repeat="label in labels track by $index | completeList">
{{ label }}
</li>
</ol>
</div>
</div>
The good news is that you only have a minor Angular syntax error. It is actually mentioned in the documentation:
Filters should be applied to the expression, before specifying a
tracking expression.
...
For example: 'item in items | filter:searchText track by item.id' is a pattern that might be used to apply a filter to items in conjunction with a tracking expression.
Given this knowledge, just change your ngRepeat line to the following, it does work exactly as you intended and works perfectly on my side:
<li ng-repeat="label in labels | completeList track by $index">
I do not know what the data structure of labels so here is my best stab at it. Filters are applied onto the instance of your iteration of your loop. It looks like you may be trying to apply the filter to the entire collection instead of that index of the loop. The filter is applied to label not labels. In this case you cannot split it. Again I dont know your data structure so I am kind of guessing here. It would be helpful if you could reveal what labels is.
Thanks,
Jordan
I need to write a script with Selenium-Webdriver. I am stuck in a situation where I need to enter text (e.g : "tt") in the textbox and a list gets populated (hidden values). We need to select an option from the populated list. (Like we do in "Google" search).
<div class="select2-search">
<input type="text" autocomplete="off" class="select2-input tabindex="-1" style>
</div>
<ul class="select2-results">
<li class="select2-results-dept-0 select2-result select2-result-selectable select2-new">
<div class="select2-result-label">
<span class="select2-match">et</span>
</div>
</li>
<li class="select2-results-dept-0 select2-result select2-result-selectable select2-highlighted">
<div class="select2-result-label">"Secr"
<span class="select2-match">et</span>"ary"
</div>
</li>
<ul>
So i'll write a little code to help you.
I'm using www.google.com as exemple.
WebElement inputElement = driver.findElement(By.id("gbqfq")); // get the input
inputElement.sendKeys("zyzz"); // you want to search him on internet ;)
// get all suggestions in a list
List<WebElement> suggestionList = driver.findElements(By.CssSelector(".gsq_a table tbody tr td:first-of-type span"));
To select an option you have 2 choices, first :
// you get a random option and click on it
suggestionList.get(1).click();
or
// you only want to click on the link that contains that.
for(WebElement elem: suggestionList)
{
String text = elem.getText();
if(text.equals("zyzz motivation"))
elem.click();
}