我使用角度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
方法中。
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;
模板代码
<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;