htmlElement.getElementsByTagName未返回数组中的预期条目

时间:2016-03-25 07:37:35

标签: html angular

我使用角度2,它使用ngFor循环动态构建一组<li>。如果我在chrome调试器中查看生成的html,我会看到li的预期数量。

我使用以下内容获取html元素 @ViewChild('myitems') itemsEl : ElementRef;

然后 var items = this.itemsEl.nativeElement.getElementsByTagName("li");

项目长度将为1,应该是3,说3.我最初在<ul>上有#myitems。我尝试将它在树中移动到div。相同的结果。

我已将其归结为ElementRef.nativeElement,而不是返回与检索到的document.getElementById(..)元素相同的结果

这是原始问题的片段。我希望item和items_2数组具有相同的长度,但它们不会。如果我避开ElementRef,它就可以工作。

   var myItemsElement = document.getElementById("myitemsById");
    var items = myItemsElement.getElementsByTagName("li");

    // invalid count of items
    var items_2 = this.itemsElementRef.nativeElement.getElementsByTagName("li");

为什么我没有从.getElementsByTagName获得正确数量的元素。我正在使用beta 9,这曾经用elementRefs编码,但它停止工作。我担心它是一个有角度的bug。我可以编写代码来解决这个问题,但我关注的是更深层次的问题。

组件代码 - 错误在checkForScroll方法中。

&#13;
&#13;
import {Component, View, Inject, forwardRef, Input, ViewChild, ViewEncapsulation} from 'angular2/core';
import {FORM_DIRECTIVES, ControlGroup,Control,CORE_DIRECTIVES} from 'angular2/common';
import {Validators,NgIf,NgFor} from 'angular2/common';
import {MixService} from "../player/mixService";
import {MixSegment,Video} from "../appTypes";
import {SegmentProgressBar} from "./SegmentProgressBar";

import {BrowserDomAdapter} from "angular2/src/platform/browser/browser_adapter";
import {ElementRef} from "angular2/core";

import {Ruler, Rectangle} from 'angular2/src/platform/browser/ruler';
import {PubSub} from "../util/pubsub";
import {PubSubTopic} from "../appTypes";
import {AppInfo} from "../util/appinfo";

// selecting text programmatically
//inputElement.$.input.select()

@Component({
    selector: 'mix-console',
})
@View({
    templateUrl: "./mixComponents/mixconsole.html",
    directives: [
        FORM_DIRECTIVES,NgIf,NgFor,SegmentProgressBar
    ]
    ,encapsulation: ViewEncapsulation.None
})
export class MixConsole {
    @ViewChild('myitems')  itemsElementRef : ElementRef;
    @ViewChild('scrollableArea')  scrollableAreaElementRef : ElementRef;
    mixService : MixService ;
    pubsub : PubSub ;

    myForm: ControlGroup = new ControlGroup({
        segmentName: new Control(""),
        segmentDescription : new Control("")
    });

    // form controls
    _segmentNameControl : Control = <Control> this.myForm.controls['segmentName'];
    _segmentDescriptionControl : Control = <Control> this.myForm.controls['segmentDescription'];

    constructor(private appInfo:AppInfo, mixService:MixService, pubsub : PubSub) {
        var self = this ;
        console.log("ctor.MixConsole");
        this.mixService = mixService ;
        this.pubsub = pubsub ;

        // let's subscribe to the segment changed event, so we can watch to
        // see if we need to scroll
        this.pubsub.getObserver(PubSubTopic.segmentChanged).subscribe((segment)=> {
            console.log("mixconsole.got.segmentChanged",segment) ;
            self.checkForScroll(segment) ;
        });
    }


    ngAfterViewInit(){
        // this isn't necessary in this context, but the docs, say it is.
        // i did it, keeping around for reference
        // var myDialog = this.paperCardEl.nativeElement ;
        // this.scrollableEl.nativeElement.dialogElement = myDialog ;
        console.log("scrollableArea",this.scrollableAreaElementRef.nativeElement) ;
    }

    checkForScroll =(segment)=> {

        // What?
        var myItemsElement = document.getElementById("myitemsById");
        var items = myItemsElement.getElementsByTagName("li");


        // invalid count of items
        var items_2 = this.itemsElementRef.nativeElement.getElementsByTagName("li");

        if (items_2.count != items.count) {
            console.log("Error item arrays should be the same length",items.count,items_2.count) ;
        }

        var itemHeights = [] ;
        var scrollTop = 0 ;
        for (var i = 0;  i < items.length; i++ ) {
            var height = items[i].offsetHeight ;

            itemHeights.push(
                {height:height,
                 scrollTop:scrollTop,
                 bottom:height+scrollTop,
                 name:this.mixService.mix.segments[i].name
                }) ;

            scrollTop += height ;
        }
        console.log("items.li",items) ;
        console.log("itemHeights",itemHeights) ;
        
        var currentSegmentIndex = this.mixService.mix.segments.indexOf(this.mixService.mix.currentSegment) ;
        var currentItem = itemHeights[currentSegmentIndex];

        // What?

        // this is correct
        var scrollableAreaElement = document.getElementById("scrollableAreaById");
        var heightOfContainer = scrollableAreaElement.offsetHeight ; // returns correct number

        // this is not, return 0
        var heightOfContainer2 = this.scrollableAreaElementRef.nativeElement.offsetHeight ;

        if (heightOfContainer != heightOfContainer2) {
            console.log("Height of the container should be the same",heightOfContainer,heightOfContainer2) ;
        }



        var currentScrollTop = this.scrollableAreaElementRef.nativeElement.scrollTop ;

        //console.log("heightOfContainer",heightOfContainer,"currentScrollTop",currentScrollTop);
        //console.log("Item Heights:",itemHeights,"currentSegment:",this.mixService.mix.currentSegment.name) ;

        if (currentScrollTop > currentItem.scrollTop) {
            // current item is above the viewport, scrroll this item to the top
            this.scrollableAreaElementRef.nativeElement.scrollTop = currentItem.scrollTop ;
        } else if (currentScrollTop + heightOfContainer < currentItem.bottom){
            console.log("Needs scroll",this.mixService.mix.currentSegment.name) ;
            if (currentSegmentIndex > 0) {
                // this puts the active segment one item down from the top,
                // i'm thinking it's more important to see what's coming up
                // as opposed to what's in the past.
                var topItem = itemHeights[currentSegmentIndex-1] ;
                this.scrollableAreaElementRef.nativeElement.scrollTop = topItem.scrollTop ;
            }
        } else {
           //console.log("Does not need scroll") ;
        }
    }

    onPlayMix() {
        this.mixService.onPlayMix() ;
        this.checkForScroll(this.mixService.mix.currentSegment) ;
    }

    onPlaySegment(segment:MixSegment) {
        this.mixService.onPlaySegment(segment) ;
        this.checkForScroll(this.mixService.mix.currentSegment) ;
    }

    addSegment() {
        this.mixService.addSegment();
    }

    stashSegment(segment:MixSegment) {
        this.appInfo.segmentStash.push(this.appInfo.clone(segment)) ;
    }

}
&#13;
&#13;
&#13;

模板代码

&#13;
&#13;
<style is=“custom-style”>
    #myhtmlscrollable {
        --paper-dialog-scrollable: {
            padding-left: 0px;
            padding-right: 0px;
        };
    }
</style>

<form [ngFormModel]="myForm">
<div  class="layout horizontal">
    <paper-dialog #paperheader  class="layout flex" style="background-color: white;max-height: 450px">
        <div id="scrollableAreaById" #scrollableArea  style="max-height: 401px;overflow: auto">
            <ul id="myitemsById" #myitems class="list-group">
                <li *ngFor="#segment of mixService.mix.segments, #i=index" class="list-group-item"
                    style="padding-top: 0px;padding-bottom: 0px"
                    (offsetHeight)="console.log('offsetHeight',$event)"
                >

                    <div class="layout horizontal" [style.backgroundColor]="segment == mixService.mix.currentSegment ? 'beige' : 'white'">
                        <!--Segment Name-->
                        <div>
                            <paper-input label="Segment Name:"
                                         style="min-width: 350px;margin-right: 10px"
                                         id="segmentName{{i}}"
                                         [ngDefaultControl]
                                         [ngFormControl]="_segmentNameControl"
                                         [(ngModel)]="segment.name">
                            </paper-input>
                        </div>

                        <!--Segment Progress Bar-->
                        <div class="layout flex" style="height: 53px;">
                            <segment-progress-bar [segment]="segment" ></segment-progress-bar>
                        </div>

                        <!--IsEnabled-->
                        <div>
                            <div class="layout vertical">
                                <div>
                                    <paper-checkbox [attr.checked]="segment.isEnabled ? true : null"
                                                    (checked-changed)="segment.isEnabled = $event.detail.value"
                                                    id="enableSegment{{i}}"
                                                    style="margin-top: 10px;"
                                    >Is Enabled</paper-checkbox>
                                    <paper-tooltip for="enableSegment{{i}}">Enable/Disable for playback</paper-tooltip>
                                </div>
                                <div>
                                    <paper-icon-button id="stashSegment{{i}}" icon="content-copy" (click)="stashSegment(segment)"
                                                       style="padding:4px;"
                                    ></paper-icon-button>
                                    <paper-tooltip for="stashSegment{{i}}">Stash Segment</paper-tooltip>
                                </div>
                            </div>
                        </div>

                        <!--move segment up/down-->
                        <div class="layout vertical">
                            <div>
                                <paper-icon-button icon="hardware:keyboard-arrow-up"
                                                   id="moveSegmentUp{{i}}"
                                                   (click)="mixService.onMoveSegment(segment,'up')"
                                                   style="padding:0px;"
                                ></paper-icon-button>
                                <paper-tooltip for="moveSegmentUp{{i}}">Move Segment Up</paper-tooltip>

                            </div>
                            <div>
                                <paper-icon-button icon="hardware:keyboard-arrow-down"
                                                   id="moveSegmentDown"
                                                   (click)="mixService.onMoveSegment(segment,'down')"
                                                   style="padding:0px;margin-top: -10px"
                                ></paper-icon-button>
                                <paper-tooltip for="moveSegmentDown{{i}}">Move Segment Down</paper-tooltip>
                            </div>
                        </div>

                        <!--play button-->
                        <div class="layout vertical">
                            <div>
                                <paper-icon-button id="playSegment{{i}}" icon="av:play-circle-filled" (click)="onPlaySegment(segment)"
                                                   style="padding:4px;"
                                ></paper-icon-button>
                                <paper-tooltip for="playSegment{{i}}">Play Segment</paper-tooltip>
                            </div>
                            <div>
                                <paper-icon-button id="deleteSegment{{i}}" icon="delete" (click)="mixService.deleteSegment(segment)"
                                                   style="padding:4px;"
                                ></paper-icon-button>
                                <paper-tooltip for="deleteSegment{{i}}">Delete Segment</paper-tooltip>
                            </div>
                        </div>
                    </div>

                    <div class="layout horizontal" [style.backgroundColor]="segment == mixService.mix.currentSegment ? 'beige' : 'white'">
                        <!--Segment Description-->
                        <div class="flex">
                            <paper-textarea label="Segment Description:"
                                            style="min-width: 200px"
                                            id="segmentDescription{{i}}"
                                            [ngDefaultControl]
                                            [ngFormControl]="_segmentDescriptionControl"
                                            [(ngModel)]="segment.description">
                            </paper-textarea>
                        </div>
                    </div>
                </li>
            </ul>
        </div>


    </paper-dialog>
</div>
</form>
&#13;
&#13;
&#13;

0 个答案:

没有答案