0

I have an alert system, and the user needs to be able to create an unlimited number of alerts and add an unlimited number of triggers to each alert.

For instance the user may have an alert called "When prices change on my cars". They need to be able to create a trigger of the same type ("Price Change") for each of the cars they want to follow.

What follows is a stripped-down version, only dealing with the triggers.

Here's a plunker - just press Add twice and you'll see the issues.

JS

// the array of trigger possibilities
$scope.triggerOptions = [
  {id : 0, type: 1, action: "Status Update For Brand"},
  {id : 1, type: 2, action: "Price Changed for "}
];

// the model for the select element
$scope.selected = $scope.triggerOptions[0];

// this array will hold all the triggers created
$scope.triggers = [];

// add some indexes to the new trigger object, then add it to triggers
$scope.addTrigger = function() {
  var newTrigger = $scope.selected;
  var newID = $scope.triggers.length;
  var alertID = 0; // todo: apply alert id
  newTrigger.triggerID = newID;
  newTrigger.alertID = alertID;
  $scope.triggers.push(newTrigger);
};

HTML

<select ng-options = "option.action for option in triggerOptions track by option.id" ng-model = "selected"></select>
<button ng-click="addTrigger()">Add</button>

<div ng-repeat="trigger in triggers track by triggerID" class="alert-tool-action-box">
  <div ng-show="trigger.type==1">
    <div>{{trigger.action}}</div>
  </div>

  <div ng-show="trigger.type==2">
    <div>{{trigger.action}}</div>
  </div>
</div>

Issues

  • When I add more than one trigger, only the first trigger is shown, but I get a "dupes" error message (which suggests I add a 'track by', but I already did).
  • When I add two triggers of the same type in a row, the triggerID is updated to the new triggerID for both triggers:

one trigger:

[{"id":0,"type":1,"action":"Status Update For Brand","triggerID":0,"alertID":0}]

two triggers:

[
  {"id":0,"type":1,"action":"Status Update For Brand","triggerID":1,"alertID":0},
  {"id":0,"type":1,"action":"Status Update For Brand","triggerID":1,"alertID":0}
]

I should be able to see each trigger as I add them, even if they're the same as the one before.

2
  • TL;DR; track by must be unique so triggerID can't contain dupes. You can always try and track by $index. Commented Aug 18, 2016 at 17:41
  • 1
    Or not using track by at all. But why do you have two triggers with the same ID in the first place? Isn't an ID supposed to uniquely identify a trigger? Commented Aug 18, 2016 at 17:42

3 Answers 3

2

Your array of objects can't contain duplicates (Error: [ngRepeat:dupes]), now these two objects are equal. This can be solved using track by, which must be unique, so triggerID can't be used here. You can always use track by $index (provided by ng-repeat directive) if no unique property is available.

Sign up to request clarification or add additional context in comments.

1 Comment

triggerID is set to the length of the trigger array, so it won't be unique, right? I mean every time an object is added, that number changes. But thanks for the $index idea, I'll try that.
2

About your second problem, you are always pushing the same object, as you only have 1 instance of the $scope. To solve that, you just need to clone (or copy) the $scope.selected, like this:

var newTrigger = angular.copy($scope.selected);

Hope it helps!

1 Comment

That fixes the issue of the triggerID being set, but still only one trigger shows up even though there are many triggers in the triggers object. plnkr.co/edit/yn6t8PHN1QRXOzy4uv7q?p=preview
1
  • You ng-repeat show only one representant of you array because you track by triggerID which don't exist (angular should search it on the $scope and return undefined each time it call it). The good way to call triggerID will be trigger.triggerID. So :

     <div ng-repeat="trigger in triggers" class="alert-tool-action-box">
      ....
    </div>
    

    or if you want to use track by :

    <div ng-repeat="trigger in triggers track by trigger.triggerID class="alert-tool-action-box">
      ....
    </div>
    
  • Your second issue is linked to the fact that javascript pass object by reference and not by value. You don't create a new object. You just pass the same and change its value. It's why you have all your object that are updated with the same id. So you can use angular.copy() to make it different object. Something like :

     $scope.addTrigger = function() {
       var newTrigger = angular.copy($scope.selected);
       var newID = $scope.triggers.length;
       var alertID = 0; // todo: apply alert id
       newTrigger.triggerID = newID;
       newTrigger.alertID = alertID;
       $scope.triggers.push(newTrigger);
    };
    

3 Comments

Oh, OK. I thought by assigning selected to a new variable, it was creating a new instance. Thanks!
For primary value, yes. Not for object.
OK, I removed the track by from ng-repeat, although I don't understand your explanation as to why this worked and tracking by triggerID didn't - the triggerIDs need to be unique - are they not unique?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.