6

Let's say that somewhere in my template I'm using:

<div *ng-for="#fooItem of foo">
    {{fooItem.bar.baz.value}}
</div>

I would like to be able to write something like {{theBaz}} instead of using fooItem.bar.baz every time in my loop. Is there a way to achieve that? Maybe some syntax that allows to define arbitrary variables?

The documentation mentions usages that involve components/directives setting the value, but apparently nothing simpler.

dgn
  • 1,213
  • 2
  • 13
  • 20
  • Possible duplicate of [How to declare a variable in a template in Angular2](http://stackoverflow.com/questions/38582293/how-to-declare-a-variable-in-a-template-in-angular2) – Louis Mar 17 '17 at 12:07

1 Answers1

3

One possible solution would be with a small Angular2 Pipe.

get-the-baz.ts:

import {Pipe} from 'angular2/angular2';

@Pipe({
    name: 'theBaz'
})

export class GetTheBaz {
    transform(item) {
        return item.bar.baz.value
    }
}

And in your app:

import {Component, bootstrap, NgFor} from 'angular2/angular2';
import {GetTheBaz} from './get-the-baz';

@Component({
    selector: 'my-app',
    directives: [NgFor],
    pipes: [GetTheBaz],
    template: `QuickApp: 
    <div *ng-for="#item of list">
        {{item|theBaz}}
    </div>
    `
})

Depending on your use case, this may or may not be a good idea.

EDIT: Two more solutions

Check out the code below I have added:

  1. piping on the list and,
  2. a good ol'fashioned function

(I also included the above pipe on an item solution for comparison)

import {Component, bootstrap, NgFor} from 'angular2/angular2';
import {Pipe} from 'angular2/angular2';

// This may not be the most efficient way, I'll do some research and edit in a moment
var _getC = val => (val && val['a'] && val.a['b'] ) ? val.a.b['c'] : null; 


@Pipe({
    name: 'pipeC'
})
export class pipeC {
    transform(val) {
        return _getC(val)
    }
}

@Pipe({
    name: 'pipeCFromList'
})
export class pipeCFromList {
    transform(list) {
        return list.map(_getC);
    }
}

@Component({
    selector: 'my-app',
    directives: [NgFor],
    pipes: [pipeC, pipeCFromList],
    template: `QuickApp:
    <p>pipe item:</p> 
    <div *ng-for="#item of list">
        <item [text-content]="item|pipeC"> </item>
    </div>

    <p>pipe list:</p>
    <div *ng-for="#num of list|pipeCFromList">
        <item [text-content]="num"> </item>
</div>
    <p>func item:</p>
    <div *ng-for="#item of list">
        <item [text-content]="getC(item)"> </item>
</div>
    `
})

class AppComponent {
    public getC (val) {
        return _getC(val);
    };
    list = [{a:{b:{c:1}}}]
}
bootstrap(AppComponent);

Try these on for size as well^

Ashley Coolman
  • 11,095
  • 5
  • 59
  • 81
  • 1
    Thanks. Cool solution. Leaving it open in case someone suggests something better. I think a hidden input field would also work but that's not really pretty. – dgn Nov 17 '15 at 17:56
  • 1
    I definately get your hesitation, its not great. I guess ultimately you are going to have to put your propertly access logic _somewhere_. If you could of done destructured assignment in the `ng-for` that would of been another option. You may infact find just putting it _all out there to see_ might be the best option. Or of course a good old fashioned rethink. Either way, g'luck – Ashley Coolman Nov 17 '15 at 20:56