4

1 ISSUE


I am trying to implement the following:

I have a container component ContainerComponent and child components ChildComponent. I want to modify the rendering and overall behaviour of the child components via the controlling ContainerComponent.


2 TECHNOLOGIES USED


Angular2, HTML, CSS, Javascript, Typescript, ES6


3 CODE


ContainerComponent.ts

export class ContainerComponent {

    children: Array<Child>;

    constructor(
        private _el: ElementRef,
        private _dcl: DynamicComponentLoader,
        private _childService: ChildService) {

    }

    ngOnInit() {

        let index = 0; // index of child component in container
        this._childService.getChildren().then( // get the children models
            (children) => {

                this.children = children; 
                this.children.forEach((child, index) => {
                    this._dcl.loadIntoLocation(ChildComponent, this._el, 'dynamicChild')
                    .then(function(el){
                        el.instance.child = child; // assign child model to child component
                        el.instance.index = index;
                    });
                });

            }
        );

    }

}

ChildComponent.ts

export class ChildComponent {

    child: Child;
    index: number;

    constructor(private _renderer: Renderer, private _el: ElementRef) {
    }

    ngOnInit() {

        let delay = (this.index + 1) * 0.5; // calculate animation delay
        this._renderer.setElementStyle(this._el, '-webkit-animation-delay', delay + 's !important');
        this._renderer.setElementStyle(this._el, 'animation-delay', delay + 's !important');

    }

}

4 CODE EXPLANATION


In the above code, the ContainerComponent dynamically inserts ChildComponents (granted, this could be done without the DynamicContentLoader).

The ChildComponents should dynamically add css properties, in this case, the animation delay once it is displayed. So based on the index of the child, the animation delay increases.

However the modifications from the renderer do not take effect, the css properties are not there at runtime.

the_critic
  • 12,720
  • 19
  • 67
  • 115
  • 2
    Wild guess: is ngOnInit() too early in the [component lifecycle](https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html)? Does ngAfterContentInit() or ngAfterViewInit() work instead? – Mark Rajcok Dec 28 '15 at 22:51
  • 2
    @MarkRajcok Appreciate your input, but unfortunately it does not affect the component regardless of where I put it. – the_critic Dec 29 '15 at 01:25
  • Another wild guess: What happens when you add `implements OnInit` (i.e. `class ChildComponent implements OnInit { ... }`). At least, that's what I understand from the doc: https://angular.io/docs/js/latest/api/core/OnInit-interface.html – MartyIX Jan 04 '16 at 14:19
  • 1
    @MartinVseticka Yes! That's it! Please post an answer so that I can reward you good Sir! – the_critic Jan 04 '16 at 14:27
  • I posted it as an answer. I'm glad it helped. :) – MartyIX Jan 04 '16 at 14:33
  • can you inject css with predefined animation styles and then add the class to the element - that might get around the problem of adding animation styles on the fly? – A Macdonald Jan 06 '16 at 11:58
  • Let me see if I understand correctly, all you want to do is set the class `-webkit-animation-delay` with a different value on each child? – Langley Jan 08 '16 at 22:45
  • @Langley That is correct, yes. – the_critic Jan 08 '16 at 22:45
  • why don't you do it using a template? – Langley Jan 08 '16 at 22:46

3 Answers3

1

I tried to reproduce your problem. In fact, I have problem to add styles like -webkit-animation-delay and animation-delay.

If I try with another style like color, it works fine and the style is taken into account at runtime.

ngOnInit() {
    this._renderer.setElementStyle(this._el, 'color', 'yellow');
}

So it seems to be linked to animation styles... I see these links that could interest you:

Otherwise it seems that there is some support for animation in Angular2 but it's not really documented... See this file: https://github.com/angular/angular/blob/master/modules/angular2/src/animate/animation.ts.

Hope it helps you, Thierry

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
0

This seems to be a bug in angular2 itself. Adding !important to a style will result in an illegal value to the style and it is not applied to the element. The correct way in plain js is to use another parameter which implies if the style is important.

So the correct answer is to use:

this._renderer.setElementStyle(this._el, 'animation-delay', delay + 's'); //sans !important

and if you want to add !important you have to use:

this._el.nativeElement.style.setProperty('animation-delay', delay + 's', 'important');

The -webkit- prefix gets added (or removed) if necessary, so there is no need to add that as well

Poul Kruijt
  • 69,713
  • 12
  • 145
  • 149
0

From here:

https://angular.io/docs/ts/latest/api/core/ElementRef-class.html

You should only use ElementRef as an absolute last resource. The whole idea of Angular 2 is that you don't have to mess with the dom at all. What you are trying to do can be acomplished very easy using a template:

import {NgStyle} from 'angular2/common';
import {Component} from "angular2/core";

@Component({
    selector: 'app',
    template: `
        <div *ngFor="#child of children; #i = index">
            <div [ngStyle]="{ 'z-index': i * multiplier,
                                '-webkit-animation-delay': i * multiplier + 's',
                                 'animation-delay': i * multiplier + 's' }"> {{i}} - {{child}} </div>
        </div>
    `,
    directives: [NgStyle]
})
export class AppComponent{
    public children:string[] = [ "Larry", "Moe", "Curly" ];
    public multiplier:number = 2;
}

Depending on the browser you might see those css properties or not, that's why I added the z-index which is more common and old so you can see you can render the css value dynamically using the index variable from ngFor inside a template.

I hope this helps !

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
Langley
  • 5,326
  • 2
  • 26
  • 42
  • I think you do have a valid point right there, but I would love to keep this more dynamic that's why I probably won't pick/use your answer (but I might...). – the_critic Jan 09 '16 at 10:11