Accessing the previous element in a loop {{#each}}

I am wondering how to access the previous item in a {{#each items}} loop. For example, Template.index.messages returns an array of objects with name and message:

{{#each messages}}
  {{#if previousMessage.name != this.name }}
    {{name}}
  {{/if}}
  {{this.message}} 
{{/each}}

      

Basically I would like to hide the name in sequential posts. I did a workaround by filtering the messages in Template.index.messages, but this method is called every time the data changes and therefore costs a lot of resources. So how do you do this in space?

Thanks in advance.

+3


source to share


4 answers


The Spacebars template language isn't really built for complex logic, so I wouldn't try to do it right in the template itself. No matter where you implement the name-hiding code, it will use resources, so doing it in a helper function as you already are is probably the easiest / best way to do it. As a side note, it spacebars

does not handle equality assertions, such as !=

, for this you must make a helper function.

If you are really concerned about the computation time, the only way to reduce it is to store more data in the database (like the name of the last post). If you keep this (like in .previousName

) it will be as simple as:

In the template:



{{#each messages}}
    {{#if notEqual previousName name}}
        {{name}}
    {{/if}}
    {{message}}
{{/each}}

      

In javascript:

Template.index.helpers({
    notEqual: function (string1, string2) {
        return string1 !== string2;
    }
});

      

0


source


You can use https://github.com/raix/Meteor-handlebar-helpers when they accept my pull request https://github.com/raix/Meteor-handlebar-helpers/pull/65

Otherwise, you can add this to your project helpers to mimic the behavior of $ mapped

UI.registerHelper("$mapped", function(arr, extended) {
    var extended = extended || false;
    if(!Array.isArray(arr)){
      try {
        arr = arr.fetch()
      }
      catch (e){
        console.log("Error in $mapped: perhaps you aren't sending in a collection or array.")
        return [];
      }
    }

    var $length = arr.length;

    var mappedArray = arr.map(function(item,index) {
      var newItem = _.clone(item);
      newItem.$length = $length;
      newItem.$index = index;
      newItem.$first = index === 0;
      newItem.$last  = index === $length-1;
      newItem.$index = index;
      if (extended) {
        newItem.$nextEl = arr[index+1];
        newItem.$prevEl = arr[index-1];
        newItem.$firstEl = arr[0];
        newItem.$lastEl = arr[$length-1];
      }
      return newItem;
    });

    return mappedArray || [];
});

      



Using

{{#each $mapped yourCursor true}}
//Getting the next & previous element 
{{$nextEl._id}}
{{$prevEl._id}}
{{/each}}

      

+1


source


I'm going to provide another answer that doesn't require any additional information to be entered into the database. The reason this can get a little hairy is if for some reason the "previous name" means it no longer exists, your template logic will be disabled. Next, you need to make sure that when you delete (or disable) this record in the database, you change the "previous name" field of all records that refer to it. It can be painful. Here's what I suggest, without the need for additional packages or data.

You can access the index of any array in the template using @index

.

So, you can do it in a template:

{{#each messages}}
  {{#if isSameName @index}}
    {{name}}
  {{/if}}
  {{this.message}} 
{{/each}}

      

and then in your helper:

Template.index.helpers({
    isSameName: (idx) => {
        // Get the messages from your local storage
        let msgs = Messages.find().fetch();
        // Lets make sure we don't get any errors from the previous message not existing
        return (msgs && msg[idx-1] && msgs[idx-1].name === msgs[idx].name);
    }
});

      

No additional storage or database traversal required.

0


source


You can use the below code to retrieve external collections.

Let's say you have a collection called Collection.Customer and Collection.RechargePlan and you use both in your template to update the Client.

Customer = {"name":"James", "rechargeplan":"monthly"};
RechargePlan = [{"rechargeplan": "monthly"},{"rechargeplan": "yearly"}];

 //Inside template, Bydefault Customer is available.
{{#each RechargePlan}}
  {{#if equals ../rechargeplan rechargeplan}}
      //Hurray Plan matches
  {{/if}}
{{/each}}

      

In the above code ../rechargeplan actually Customer.rechargeplan , .. / actually went one step up the hierarchy and then accessed the field if available, since the customer is already available to the template, this field is picked up. Likewise, if there is a collection above Client , you can use ../../ rechargeplan

0


source







All Articles