Upgrade a simple select/unselect into a proper array I can call on - angularjs

I have an ng-repeat that shows a list of items a user can 'select' and I am using the following code (stripped down example) for the selection process
<div class="panel" ng-class="{'titleSelected': titleSelected[$index]}" ng-repeat="item in listofitems">
<h1>{{item.name}}</h1>
<button class="btn btn-success" ng-click="titleSelected[$index] = !titleSelected[$index]">
<span ng-hide="titleSelected[$index]">Add to Buy List</span>
<span ng-show="titleSelected[$index]">Remove from Buy List</span>
</button>
</div>
Now this is working fine (I have also had this working using item.id to track rather than $index. i click an item, background changes colour thanks to ng-class and the button dynamically becomes a remove button
However I was expecting titleSelected to be an array of stored info, but I was clearly wrong. What I actually need is a live array that stores / removes item.id on click and I have approached this all wrong.
Also when I use filters (not shown in the code), if any item is selected and then hidden by the filters.. and brought back it loses its 'selected' status.
This is the case with both $index and item.id
I suspect little functions with push and splice are required but I also still need the simple functionality of the add remove in place as well. and in perfect sync with what has actually been selected
Any pointers appreciated
EDIT 1 : Ok by simply adding
$scope.titleSelected = [];
into my controller, and using item.id instead of $index my app is now 1) remembering the selected items between filter changes AND createing an array I can call on. However the array contains (on the first selection) an entry for every single item.
So I have 503 items, and on first click the array length jumps to 912 (no idea where this number comes from).. most of which are null, but if I click on the item with id=4 then the fourth entry becomes true i.e
null,null,null,true,null...

Done with a couple of functions bound to ng-click
$scope.basket=[];
$scope.addToBasket = function(item) {
$scope.basket.push(item);
};
$scope.removeFromBasket = function(item) {
var index = $scope.basket.indexOf(item);
if (index > -1) {
$scope.basket.splice(index, 1);
}
};
and in the HTML
<button ng-hide="titleSelected[item.id]" class="btn btn-success"
ng-click="addToBasket(item.id);titleSelected[item.id] = !titleSelected[item.id]">
Add to Buy List
</button>
<button ng-show="titleSelected[item.id]" class="btn btn-success"
ng-click="removeFromBasket(item.id);titleSelected[item.id] = !titleSelected[item.id]">
Remove from Buy List
</button>

Related

Angular.js ng-repeat unique identifier

I am using ng-repeat on a <tr> tag to populate the <td> tags with data pulled from mysql and converted into Json. This works just fine. However, one of the <td> tags that I'm using contains a button.
What I would like to do, is have each of these buttons identified somehow in the DOM, so that I can target then with specific requests.
Example: Page loads, ng-repeat repeats a button 4 times. Each of these buttons would have an ng-click attached to it. I want each of them to open and filter different information in a json file.
Am I correct in assuming that ng-repeat would simply open the same item for each button, and how would I go about making them seperate? thanks.
You can do something like this on the front-end:
<button ng-repeat="item in items track by $index" ng-click="someFunction($index)" >Something happens</button>
Then in your controller:
$scope.someFunction = function (index) {
if (index === 1):
// etc.
else...
// Or use switch, whichever works for you.
You could create the specific function on each item in the array.
<button ng-repeat="button in buttons" ng-click="button.functionName()">{{button.name}}</function>
There's $index for that. It's a very good habit to take for any of your ng-repeat. Also don't forget bind-once if your buttons UI isn't subject to modifications once the DOM has loaded.
<ul>
<li ng-repeat="page in pages">
<a ng-class="{ testClass: $index == pageNumber }" ng-click="setPageNumber($index)">{{ page }} - index is : {{$index}}</a>
</li>
</ul>
http://jsfiddle.net/bonatoc/4z1t4gsm/3/
Also you could do (using bind-once):
<button
ng-repeat="button in ::buttons track by $index"
id="button_{{$index}}"
class="{{button['css_class']}}"
...given your buttons were a JSON object as well (beware, ng-repeat likes arrays, not objects. Arrays of objects are fine):
$scope.buttons = [
0: {
'css_class': someClass,
'functionToTrigger': function(...
// ...

angular: how to make a button disabled based on a condition

Sorry for not being specific, but I'm having a blackout and am desperate.
Have been struggling for 2 days now to find the logic to do the following:
every item has a 'inCart' value. if it's 0, it's not in there, if it's below 7, it's in one of 6 'slots' depending on the value.
now i have buttons that assign each item to a value in inCart.
but if one of the items has a value in it that is 4, then I obviously don't want all the items to show a button that will assign it to 4.
<tr ng-repeat="x in myItems">
<a ng-repeat="slot in [1,2,3,4,5,6]" ng-click="addToCart(x._id, slot)"
class="btn btn-primary {{x.inCart != '0' ? 'disabled' : ''}}">
{{slot}}
</a></tr>
Thinking about it logically I know my mistake: i only look if the current item is in the cart, and if it is then it disables the button. How do I look at all the items in the cart, and if one of them is for example 4, then all the buttons that assign an a value 4 to inCart are disabled, so that I won't have multiple items with the same location inCart.
based on the approach I can fix this I am pretty sure I can make everything work better then how it is now, it's just that I can't even figure this out so let alone the more detailed issues.
You can use the ngClass directive
You can evaluate a expression with ng-class and if it's true you can apply a certain class. If not, then the class won’t be applied.
<button ng-class="{'disabled': expression}">
If you use an actual button, you can make use of ngDisabled:
<input type="button" ng-repeat="slot in [1,2,3,4,5,6]"
ng-click="addToCart(x._id, slot)"
class="btn btn-primary"
ng-disabled="x.inCart !== '0'" value="{{slot}}" />
You could call a function to check if the slot is available.
Controller
// return the slots already used
var slotsUsed = $scope.myItems.map(function (i) {return i.inCart;}).filter( function(s) { return s > 0;});
$scope.slotAvailable = function(s) {
return slotsUsed.indexOf(s) == -1;
}
View
<tr ng-repeat="x in myItems">
<td>
<a ng-repeat="slot in [1,2,3,4,5,6]"
class="btn btn-primary"
ng-click="addToCart(x._id, slot)"
ng-class="{'disabled': x.inCart != '0' || !slotAvailable(slot)}">
{{slot}}
</a>
</td>
</tr>
There's a directive designed specifically for this: ngDisabled
https://docs.angularjs.org/api/ng/directive/ngDisabled

How to create dynamic expression in ng-class

I have a ngRepeat element that has a delete button that triggers a confirmation message. I'm trying to make the confirmation message show with a dynamic expression like so:
<div ng-repeat="item in items">
<a ng-click="delete(item_id)"></a>
<span ng-class="{'show':'delete_'+item._id}">Are you sure you want to delete your review? </span>
</div>
Unfortunately I can't get the expression 'delete_'+item._id to show up in the ngClass directive. Can someone please offer a solution?
Using ng-class="{'show': 'delete_' + item._id}" will add the class show whenever the expression 'delete_' + item._id' evaluates to true (which is always). You probably want to have an expression next to show which is true when the user has clicked the a tag, i.e. ng-class="{'show': userWantsToDelete(item)}".
Additionally, if you want to add the class 'delete_' + item._id to the element, you can use angular expressions with class attribute, i.e., class="{{'delete_' + item._id}}" on the element.
try this one.
<a ng-click="delete = !delete">delete</a>
<span ng-class="{show: delete}">Are you sure you want to delete your review? </span>
if you want to show one delete confirmation message of last clicked <a>
In view
<a ng-click="delete(item._id)">delete</a>
<span ng-class="{show: item._id==delete_id}">Are you sure you want to delete your review? </span>
In controller
$scope.delete = function(id) {
$scope.delete_id = ($scope.delete_id == id) ? !id : id;
}

Both "clickable" and "draggable" area

I have a list of element inside an ng-repeat for which elements are clickable and draggable : if I click I display, and if I drag ... I drag the element.
When dragging I am displaying a circle with the number of element to drag.
My problem is that when a click, the drag circle is displayed. Whereas I just want to click and not drag.
Is there a way to set like 2s when clicking, like a long press action (with the mouse) to distinguish the click from the drag actions ?
It is similar to this post but now I want to prevent the drag when clicking (in the Angular way).
Here some markup :
<div class="docs-manager-doc box-container" ng-class="{'showActions':doc.showActions}">
<a class="box-square" ng-href ng-click="docsManager.toggleDocumentSelection(doc)">
<span class="flaticon-dark"
ng-class="{ 'flaticon-video-embed':(!doc.selected && doc.ref && doc.targetType==='EMBEDDED_VIDEO'),
'flaticon-{{doc.label | docExtMap}}':!doc.selected && !doc.ref,
'flaticon-tick':doc.selected }" ibp-prevent-drag>
</span>
</a>
<a ng-drag="true" ng-drag-data="doc" ng-drag-success="onDragComplete($data)" ng-drag-begin="onDragStart($data)" ng-drag-stop-move="onDragStop($data, $event)">
<span class="box-drag">
<span class="dragging" ng-show="iamdragging" >
<span class="flaticon-dark flaticon-small">
<p class="flaticon-default-doc">{{docsManager.documents.selected.length}}</p>
</span>
</span>
</span>
</a>
</div>
I am using ngDraggable directive.
Here some code if it helps :
.controller('DocumentsManagerCtrl', ['...',
function(...) {
$scope.iamdragging = false;
$scope.onDragStop = function(data, event){
$scope.iamdragging = false;
};
$scope.onDragStart = function(data){
if(!data.selected){
$scope.docsManager.toggleDocumentSelection(data);
}
$scope.iamdragging = true;
};
$scope.onDragComplete = function(){
// do something
};
May be it could be good to have a directive like ng-click-or-drag, when the click is more than 2s it is interpreted as a drag.
The issue has been solved here partially. https://github.com/fatlinesofcode/ngDraggable/issues/12. Posting in case it is useful to someone else browsing the question.
Setting ng-prevent-drag="true" on any element that you do want to initiate drag action, disables the drag action initiation on that object.
I guess benek who has asked this question is also involved in the discussion in the link above. he has indicated that this breaks on ipad, however I have tested this on laptop where it works.
I have implemented ng-drag-after-timeout="2000" attribute which allows to manage this.
The patch is here https://github.com/advantiss/ngDraggable/commit/51bd0e16b3f363935b249b2ee185968f4999f87d
I fixed this by making my image (which was a problem) a vice .
The DIV had a background-image: url();
Problem solved for me

ng-click different behaviour when clicking second time

Below is my HTML
<div id="alertmap-buttons" class="span2 no-margin">
<button id="alert-add-location" class="btn btn-default pull-left" ng-click="displayMap = !displayMap"><span ng-if="!displayMap">Add Location</span><span ng-if="displayMap">Done</span></button>
<button id="alert-cancel-location" class="btn btn-danger" ng-if="displayMap" ng-click="alert.latitude = !alert.latitude; alert.longitude = !alert.longitude;">Cancel</button>
</div>
<div ng-if="alert.latitude && alert.longitude" id="latlng-label" class='span3 pull-right no-margin'>
<div class="pull-left"><label class="latlng-label">lat: {{alert.latitude}}</label></div>
<div class="pull-right"><label class="latlng-label">long: {{alert.longitude}}</label></div>
</div>
Here am trying to hide lat & long when clicking on Cancel button, but when I clicked on Cancel button second time it is again showing as
lat:true lang:true
What should be done here to remove this?
And one more thing, here displayMap is diplaying a map to choose lat and lang, after choosing when we click Done map will be disappeared and a form will be shown to the user. All these things will happen in a modal dialog box. Here when I click on Cancel I need to clear the values of lat & long also I need to do this
displayMap = !displayMap
But this combination is not working? Any ideas on this?
Thanks
You are reversing the value. Stop reversing it and set the value to false.
ng-click="alert.latitude = false; alert.longitude = false;"
UPDATE:
ng-click="displayMap = !displayMap; alert.latitude = false; alert.longitude = false;"
But as this is getting a bit verbose I would probably create a function in my controller to reset these values. As far as I know with ng-click you can make it do as many things as you want as long as they are semi-colon separated.

Resources