jmilloy
jmilloy

Reputation: 8365

Access an element's object model in angular?

Is it possible to access an element's model from the element?

Background

I'm trying to make a change to the way Ionic's ion slides work. There is a Slides component and a Slide component, and usage is like this:

<ion-slides>
  <ion-slide> Slide 1 </ion-slide>
  <ion-slide> Slide 2 </ion-slide>
</ion-slides>

Each Slide requires a reference to it's parent Slides. It's implemented like this:

export var Slide = (function () {
    function Slide(elementRef, slides) {
        this.slides = slides;
        this.ele = elementRef.nativeElement;
        this.ele.classList.add('swiper-slide');
        slides.rapidUpdate();
    }
    ...
    Slide.prototype.ngOnDestroy = function () {
        this.slides.rapidUpdate();
    };
    Slide.decorators = [
        { type: Component, args: [{
                    selector: 'ion-slide',
                    template: '<div class="slide-zoom"><ng-content></ng-content></div>',
                    changeDetection: ChangeDetectionStrategy.OnPush,
                    encapsulation: ViewEncapsulation.None,
                },] },
    ];
    Slide.ctorParameters = [
        { type: ElementRef, },
        { type: Slides, decorators: [{ type: Host },] },
    ];
    Slide.propDecorators = {
        'zoom': [{ type: Input },],
    };
    return Slide;
}());

This means that you can't use an ion-slide without a ion-slides parent without getting a template parse error, e.g. in a custom ion-slide wrapper such as:

@Component({
  selector: 'myslide',
  template: '<ion-slide> <h1> Test Header </h1> <ng-content></ng-content> </ion-slide>',
})
export class MySlide {
  constructor() {}
}

with

<ion-slides>
    <myslide> Slide 1 </myslide>
    <myslide> Slide 2 </myslide>
</ion-slides>

Question

I'm trying to modify the ionic slides code to allow a Slide without a Slides parent by having the Slides pass a reference to itself to each child Slide after init. I can easily access the ion-slide DOM elements that are children of a Slides component, but how can I access their angular model?

What I tried

1) During Slides init, I can select the ion-slides elements just fine. How can I access the model for these elements? Really, I only need to set the slides model variable.

Slides.prototype.ngOnInit = function () {
    // this query works
    var slide_elems = this.getNativeElement().querySelectorAll('ion-slide');

    // this obviously doesn't work because
    // slides needs to be a attribute of the model,
    // not the DOM elem
    slide_elems[0].slides = this;

2) @matej-maloča suggested ViewChild. Really it looks like I need ContentChildren, so I added a ContentChildren selector to the Slides.

Slides.decorators = [
        { type: Component, args: [{
                    selector: 'ion-slides',
                    template: '<div class="swiper-container">' +
                        '<div class="swiper-wrapper">' +
                        '<ng-content></ng-content>' +
                        '</div>' +
                        '<div [class.hide]="!showPager" class="swiper-pagination"></div>' +
                        '</div>',
                    changeDetection: ChangeDetectionStrategy.OnPush,
                    encapsulation: ViewEncapsulation.None,
                    queries: {
                        'ionSlides': new ContentChildren(Slide)
                    },
                },] },
    ];

This almost works. It selects Slide components that are in the content of the ion-slides element itself but not ones inside a container component (e.g. the custom myslide). Is there a way to select those nested ion-slides elements as well?

<ion-slides>
  <-- selected by ContentChildren -->
  <ion-slide>Slide 1</ion-slide>
  <ion-slide>Slide 2</ion-slide>

  <-- the ion-slide within myslide is not selected!! -->
  <myslide>Slide 3</myslide>
</ion-slides>

Notes

I went looking for a link to the source for ion-slides and found this, which is in typescript. What can I do to update the version I have in my node_modules/ionic-angular to this? Currently everything there is defined in javascript which is a little bit harder to work with.

Upvotes: 1

Views: 1673

Answers (1)

Matej Maloča
Matej Maloča

Reputation: 974

You need to use ViewChild.

// it's variable
@ViewChild('ion-slide') elem: any;

In ngOnInit:

this.elem.nativeElement

See docs for further questions: angular docs

If it doesn't work try to get it with ViewChild on life cycle hook ngAfterViewInit

Upvotes: 3

Related Questions