0

I have been trying to dynamically change the array number of my expression. My initial state:

<p class="title text-center">{{data[0].title}}</p>
<p class="subtitle text-center">{{data[0].sub_title}}</p>

Data is just an array returned from an http request. What I want is that when I click or swipe an element on the page that it jumps to the second item in the data array, e.g.:

  <p class="title text-center">{{data[1].title}}</p>
  <p class="subtitle text-center">{{data[1].sub_title}}</p>

I have been trying to make an expression in an expression, but I think that that is very wrong. Also, I have tried adding a variable to the $scope in the controller:

$scope.update = function (whateverispassedinfromotherfunction){
  var item = whateverispassedinfromotherfunction;

  return "data["+whateverispassedinfromotherfunction+"].sub_title";

} 

and then this in the HTML

<p class="subtitle text-center">{{update}}</p>

but that does not make any sense to Angular and to me neither :).

Anyone that knows a solution?

2 Answers 2

1

Make your current index a variable, initted to 0, and increment it. You can increment either by making a function on your controller that increments it, or just directly in a ng-click / ng-swipe.

<span ng-click="idx++"> <!-- init idx to 0 in your controller -->
    <p class="title text-center">{{data[idx].title}}</p>
    <p class="subtitle text-center">{{data[idx].sub_title}}</p>
</span>
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for this, works and easy to implement. Sometimes the solution is easier than one might think :)
1

Dylan's answer will work, but generally when you find the need for this kind of logic, you should try to wrap it up into a more general component.

For example, we'll call it Lense, as it's just a way of viewing one value at a time, given an collection of sequential values.

app.factory('Lense', function() {
  return function(values) {
    var lense = {};

    lense.index = 0;

    lense.next = function() {
      lense.index += 1;
    };

    lense.previous = function() {
      lense.index -= 1;
    };

    lense.value = function() {
      return values[lense.index];
    };
  };
});

Now you have a class which can be injected in order to create a lense which contains all of the logic for you.

You can inject it and use it anywhere you need:

function MyController($scope, Lense) {
  var data = [ { ... }, { ... }, { ... } ];
  $scope.lense = Lense(data);
}

Then your views become a lot more declarative:

<p class="title text-center">{{lense.value().title}}</p>
<p class="subtitle text-center">{{lense.value().sub_title}}</p>
<a ng-click='lense.previous()'>Previous</a>
<a ng-click='lense.next()'>Next</a>

Not only that, but it is a lot easier to write unit tests for factories than it is for directives, as they involve no rendering on HTML.

Finally, it will be a lot easier to debug. Say you want to print the value of the current index every time the user clicks next, you can just add it to your lense factory.

lense.next = function() {
  lense.index += 1;
  console.log(lense);
};

If your logic is embedded in an expression, then there's no way to do this, because console isn't a property on the current $scope.

<div ng-click='index++ && console.log(index)'></div>

3 Comments

I definitely agree that if you want to make a robust, reusable component, this is a great way to go about it. There is a time a place for a quick one off, though.
Yep, nevertheless it's always good to see both ends of the spectrum.
@DanPrince Thanks for this, I agree with you but I needed a quick solution since I am making a small demo for a company. I accepted Dylan's answer because he was first and it was exactly what I was looking for, but this is extremely useful too.

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.