alonrbar/easy-template-x

Loops capture text outside of tags

jmarks-joshua opened this issue · 7 comments

With a word document containing

The intervener(s) are {#interveners}{name}, {/}

and data of
{ interveners: [ {name: 'Test 1'}, {name: 'Test 2'} ] }

my output is

The intervener(s) are Test 1,
The intervener(s) are Test 2,

Is there any way to do this and keep it all on one line and without copying the text before my opening loop tag?

The easiest way to achieve this is to properly prepare your string when generating your template data, try something like this:

{
  intervenerString: [ {name: 'Test 1'}, {name: 'Test 2'} ].map((o) => o.name).join(', ') 
}
The intervener(s) are {intervenerString}

This way you will get rid of the trailing comma as well :)
Maybe you can event generate the complete string to get rid of the (s) as well, since you can count them....

Thanks for the suggestion, sadly I think I need a more complex solution. Building a site that will have 100ish word documents where these situations may happen frequently and should be achievable by non-tech users editing the templates.

I'm currently looking at writing my own LoopPlugin that is very similar to the current one, but with a new strategy. If I have any success I'll make a PR.

Oh yeah, in this case, this won't work. We stopped allowing our customers to modify the documents themselves since it caused more issues than it solved, unfortunately ;)

But it should not be that hard to add your own plugin to achieve this.

We had the idea to use angularFilters from https://github.com/alonrbar/easy-template-x-angular-expressions and append helper functions, like { interveners | combine("name", ", ") }, to add some functions which can be called for non-tech users since this seemed "easier" than to add multiple loop variants that behave differently with different prefixes or something, but we dropped the idea since we currently make the changes ourselves. But maybe this would be a way for you to achieve your goals. It will need some work on the resolver but should be possible and quite powerful.

Ha yeah I can totally see that potential, your original suggestion is more or less exactly what my client has right now and wanting to move away from. I want to give them as much power as possible, but it may end being a hybrid of power and precompiled strings they can use.

That's an interesting idea. I have already played around with the angularFilters feature and couldn't figure out how to pass down parameters. I had found the below syntax on the angular-expressions project, but couldn't get it to work, but I've pushed a bit harder after your suggestion and this appears to do the trick.

{interveners | combine:”name”:”, ”}

expressions.filters.combine = (input, prop, separator) => {
      return input.map((item) => item[prop]).join(separator)
};

Only thing I think needs changing is some types are getting confused because of extra arguments on the filter function, but the code runs just fine. Typescript just isn't happy about it.

It's certainly an improvement, but in an ideal world I'd actually be able to construct more of the text in the loop. This solution doesn't allow {#list}{name}: {dob}{#needsSeparator}, {/needsSeparator}{/list} which is really what I was after. So I may still have to go down a more complex route.

Anyway thanks for the help and suggestions.

Was this issue happening inside a table by any chance?

Fixed in v4.0.0