0

I'm having difficulties figuring out how to pass updated values from a click binding from one template to another. Essentially, I'm creating a component repository application where a user would be able to view a component and update options for it on the page. Most of these options are shareable between components, so I have created separate files to store these commonly used options.

With the example below, the default col-xs-4 class is being added to the component as intended, but the click event does not update the class, even though the event itself works, as logging it updates the columns value within the class. It seems that I need some sort of event listener for it to update, but I'm not sure how to handle that.


content-tout.html

<div class="row">
    <div [ng-class]="columnAmount" class="content-tout">
        Tout
    </div>
</div>

<hr />

<h2>Options</h2>
<p>Use the following buttons to update the values in the component above.</p>
<options></options>

content-tout.ts

import { Component, View, NgClass } from 'angular2/angular2';

// this is option for changing column class from the ng-class in the template
import { ColumnsOption } from '../../shared/options/columns';


@Component ({
    selector: 'contentPlaceholder',
    bindings: [ColumnsOption]
})

@View ({
    templateUrl: '/app/components/content-tout/content-tout.html',
    directives: [ColumnsOption, NgClass]
})


export class ContentTout {
    private columnAmount: string;

    constructor(private columnsOption:ColumnsOption) {
        this.columnAmount = this.columnsOption.columns;
    }
}

columns.ts

import { Component, View, NgFor } from 'angular2/angular2';

@Component ({
    selector: 'options'
})

@View ({
    template: `
        <hr />
        <h3>Columns / Width</h3>
        <nav>
            <button *ng-for="#column of columnsCollection" (click)="changeColumns(column)" class="btn btn-primary-outline" type="button">
                {{ column }}
            </button>
        </nav>
    `,
    directives: [ NgFor ]
})


export class ColumnsOption {

    private columnsCollection: Array<string> = [
        'col-xs-1', 'col-xs-2', 'col-xs-3', 'col-xs-4', 'col-xs-5', 'col-xs-6', 'col-xs-7', 'col-xs-8', 'col-xs-9', 'col-xs-10', 'col-xs-11', 'col-xs-12'
    ];
    public columns: string = "col-xs-4";


    private changeColumns(column: string) {
        this.columns = column;
    }
}

I have done much searching with click bindings in Angular2 and have only come across resources where the the example is within the same view as the binding. I'm hoping this modular approach is possible, so if anyone has any resources for me to read up on, or a particular display from the API preview, I'd very much appreciate it.

2
  • 1
    Are you looking for something like this example? Commented Nov 18, 2015 at 14:45
  • Hey, thank you so much for your response. I've noticed that the major difference here is the constructor with the injection of the class for safe usage from the host to instantiate. Anyways, this worked in my local app, so if you could explain what exactly it's doing together in an answer, I will for sure mark it. Commented Nov 18, 2015 at 19:21

1 Answer 1

3

Like you said, the example in my comment it's not that different. I'm just using @Host() to get a reference to the parent component in the child.

This is the parent and we only add a method that will modify its own column property which will be called by the child's method with the same name (just for convenience, you can call it as you wish)

@Component({
  template : `
     <div [class]="columns">{{columns}}</div>
     <columns></columns>
  `,
  directives : [Columns]
})
export class App {
  columns = "col-xs-4";
  changeColumn(column) {
    this.columns = column;
  }
}

Then in the child component the only difference, again, like you said is this code snippet

constructor(@Host() @Inject(forwardRef(() => App)) app: App) {
    this.app = app;
}

changeColumns(column) {
    this.app.changeColumn(column);
}

In the constructor I save the reference to the parent component and then in the child's method changeColumns I call the parent's method changeColumns.

Now, probably you were asking What in the world is Inject [1] and forwardRef [2] and why do I need them?. The answer is pretty simple : The child component doesn't know of its parent (App) since it doesn't exist when it's calling it. So we need them to get a reference to a class that will exist. [3]

But maybe you want to avoid using them, how? Change the order of the classes. See this little example

(Child calls Parent but it doesn't exist yet = Fail)
class Child  {}
class Parent {}

// So move parent to be above of its Child
class Parent {}
class Child {}

In the latter case you can save a few keystrokes by calling the parent as simple as follows

constructor(@Host() app: App) {
    this.app = app;
}

Adding the plnkr in the example to be part of the answer : example plnkr

I hope I was clear enough :)

Reference

[1] Documentation for @Inject()

[2] Documentation for forwardRef

[3] Classes in javascript aren't hoisted

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

1 Comment

This is perfect - describes the problem very clear with direct references for more information. 10/10, would mark your answer again. Thanks!

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.