Trigger click on first element in list in angularjs - angularjs

I'm an angularjs newbie building my first app. I have a list of users that I can filter and sort:
<button ng-click="order='lastname'; reverse=!reverse">Sort by name</button>
<button ng-click="order='id'; reverse=!reverse">Sort by id</button>
<input type="text" ng-model="filter.user">
<ul class="userlist" ng-class="{blur: currentUser}">
<li ng-repeat="user in users | orderBy:order:reverse | filter:filter.user">
{{user.id}} / {{user.firstname}} {{user.lastname}}
Show details
<div ng-click="showDetails(user)">Show details in overlay</div>
</li>
</ul>
<div ng-show="details">
<div ng-click="details=!details">close</div>
{{user.custom}}
</div>
<div ng-show="currentUser" id="overlay">
{{currentUser.firstname}} {{currentUser.lastname}} {{currentUser.custom}}
<div ng-click="closeOverlay()">close</div>
</div>
I can click on a user to get his details. Now I want to realize the following scenario: When I press the enter key in the filter text input I want to show the details of the first <li /> in the list at the current time. So in jQuery I would bind a keypress event to the input which would check for the key code (13) and then would trigger: $('li').eq(0).click() which would call showDetails() on that particular user - easy.
How can I build such functionality with angular? I tried using the ng-keypress directive which lets me bind a function to a certain keypress but now I'm stuck because I don't know how to trigger the showDetails() function on the first element. Any help greatly appreciated!

This is a workaround you can give a try for the time being: make your ng- keypress handler create a list of your filtered results (that is, reapply your filters on a copy of your user list in your controller) and then call the showDetails for the first egg element of that list.
Is it ugly? Yes. It's it a bad decision if you are working with big lists? Certainly. But it will get you going till you find another way / better stackoverflow answer.

The following should work. Inside your ng-keypress handler set a property that enter was pressed, e.g. enterPressed. Then use ng-init as follows:
<li ng-init="isFirst($first, user)" ng-repeat="user in users | orderBy:order:reverse | filter:filter.user">
{{user.id}} / {{user.firstname}} {{user.lastname}}
Show details
<div ng-click="showDetails(user)">Show details in overlay</div>
</li>
And then in your controller have something like:
$scope.isFirst = function(first, user) {
if (first && enterPressed) {
enterPressed = false;
$scope.showDetails(user);
}
}

I figured out a pretty elegant solution:
In the ng-repeat you can assign an additional variable (I called it filteredUser to the current result set:
<li ng-repeat="user in (filteredUser = (users | orderBy:order:reverse |
filter:filter.user))" ng-click="showDetails(user)">
This way it is super easy to access the first item in that result set (filteredUser[0]) and pass it to a function:
<input type="text" ng-model="filter.user" ng-keypress="$event.keyCode == 13 ?
showDetails(filteredUser[0]) : null">

Related

AngularJS when I click a link I want to filter an array

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).

Show one position of ng-repeat and reload a dropdown each time

So, I'm actually new to angularJS and I've been searching for a while and trying different ways to achieve something, but it seems impossible, to me.
I have this ng-repeat that should show only one of my 6 position array. When I click in "Change", than I should load the second and then the third and so on, until all my data have been accessed and changed by the user, that's why I limited it to 1.
The Professor's select should load according to a parameter from the current ng-repeat class. I have no idea how to solve this problem. I'm trying right now to use a service to load the professor's dropdown, but with no success.
<div class="row" **ng-repeat="class in classes | offset:currentPage | limitTo: 1"** on-finish-render="ngRepeatFinished">
<div style="display: block;">
<div>
<p><label for="">Change:</label> {{ class.professorName }}</p>
</div>
<div>
<p><label for="">By:</label>
<select id="professor" name="professor" class="form-control">
<option ng-repeat="professor in professors" value="{{professor.id}}">{{ professor.name }}</option>
</select>
</p>
</div>
</div>
</div>
<hr>
<center><button type="button" ng-click="change(class.classId)" class="btn btn-primary">Change</button></center>
</div>
What's the best way to achieve something like this (Show only one item each time and after user submits the form, go to the next position... and for each ng-repeat item, I have to reload the professors dropdown)?
Thank you!
Am I understanding you correctly, you want
ng-repeat class in classes //limit 1 //index i.e. [0] +1 change index after button click so you move to the next class index location?
If your setting a value of professor.id in the class or a property that isn't set or is null/undefined before the button, then just add this to your parent div with the loop of class in classes.
ng-if="!class.propName" //if property/dropdown not set
If this isn't what your looking for please expand on your question.

AngularJS Show List Items based on ng-model

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.

angularjs how set right scope for function?

have this ng-repeat
<li class="tmmenu-admin-tabs-builder-panel-portlet" ng-repeat="question in questions">
<div>
<span class="tmmenu-admin-tabs-builder-panel-portlet-toggler" ng-click="tatbppTogler()">{{{tatbppt}}}</span>
<span class="tmmenu-admin-tabs-builder-panel-portlet-number">{{question.id}}</span>
{{question.text}}
</div>
<div class="tmmenu-admin-tabs-builder-panel-portlet-options" ng-show="showTatbppo">
...
</div>
</li>
I want, for click in "tmmenu-admin-tabs-builder-panel-portlet-toggler" change visibility "tmmenu-admin-tabs-builder-panel-portlet-options" and change text in "tmmenu-admin-tabs-builder-panel-portlet-toggler".
And i write this code for get result:
$scope.tatbppTogler = function(){
$scope.showTatbppo = !$scope.showTatbppo;
if($scope.showTatbppo){
$scope.tatbppt = "-";
}else{
$scope.tatbppt = "+";
}
}
It's works, but changed dom in all "Li", how changed only current (where user click) "li"?
You can do it like this:
<li class=portlet" ng-repeat="question in questions">
<div>
<span class="toggler" ng-click="showTatbppo=!showTatbppo">{{showTatbppo ? "+" : "-" }}</span>
<span class="number">{{question.id}}</span>
{{question.text}}
</div>
<div class="options" ng-show="showTatbppo">
...
</div>
</li>
Working fiddle, with this concept:
http://jsfiddle.net/x1nguaxj/
btw. You have very-very-very long css class names :)
1 way
you can pass this in ng-click="tatbppTogler(this)" and then in function manipulate with this
2 way
you can create custom directive and apply it to your li element and then on this directive bind click to element and listen , and on click function will be triggered your listener and you will have access on this element
You can create an attribute id for each question and then change based on the id of the question you clicked
I would suggest you'd take a look at $index. From the angularjs docs:
iterator offset of the repeated element (0..length-1)
Using this, you can clearly determine the certain div that was clicked on.

Add fiter dynamically to ng-repeat

I want add the filters to the ng-repeat depending on there checkbox state.
<li ng-repeat="user in users | filter: filters">
{{user.name}} {{user.job}} {{user.min}}-{{user.max}}
</li>
Can filters be an array?
The second Questions is, how can i show all records, when $scope.min and $scope.max are empty (at init)?
http://jsfiddle.net/nofear87/H5GMD/3/
Yes, you can change filters dynamically quite easily, just assign a scope variable and you can modify it.
Example here: http://plnkr.co/edit/Au8KFg?p=preview
If you have
<li ng-repeat="user in users | filter: filters">
then your $scope variable is
$scope.filters = {minMax: false, ... };
As for the checkboxes, if your
<input ng-model="minMaxFilter" type="checkbox" ng-change="filters['minMax] =! filters[minMax]"/>MinMAX
if you want to just change the state of a filter
or if you want to add a new filter, you can attach a function with ng-click or just push a new value
<input ng-model="newFilterToAdd" type='text' > <button ng-click="filters.push(newFilterToAdd);">Add Filter</button>
to show all records, you need to not apply the filter (such as making it empty) or assigning a null to it
You can try adding two filters for your requirement.
<li ng-repeat="user in users | filter: searchText | minMax : filterParams">
{{user.name}} {{user.job}} {{user.min}}-{{user.max}}
</li>
Here is working Fiddle.
Hope it will help you.

Resources