当前位置:主页 > 资料 >

Ngrx, Scrolling Into DOM Elements & Components Commu
栏目分类:资料   发布日期:2018-08-01   浏览次数:

导读:本文为去找网小编(www.7zhao.net)为您推荐的Ngrx, Scrolling Into DOM Elements Components Communication,希望对您有所帮助,谢谢! My open source app, , allows to consume and create a “now” playlist – where you ca

本文为去找网小编(www.7zhao.net)为您推荐的Ngrx, Scrolling Into DOM Elements & Components Communication,希望对您有所帮助,谢谢!

欢迎访问www.7zhao.net



My open source app, , allows to consume and create a “now” playlist – where you can queue media to the playlist that is currently playing. A somewhat not too visible feature in is the ability to “reveal” the now playing track in the playlist. This article shows how I integrated ngrx, angular’s ng-for and the DOM’s scrollTo feature to support the functionality for this feature. 去找(www.7zhao.net欢迎您

Now Playlist “Reveal” Feature

As a consumer of Echoes Player, I have found it useful to find the active now playing media in the “now playlist” component. 欢迎访问www.7zhao.net

Interacting with DOM in Angular is usually achieved with the “Renderer2” service – that is considered to be one of the best practices, exposing one solid api to interact with the view – let it be DOM or other. 去找(www.7zhao.net欢迎您

The “reveal” functionality is tied to the “NOW PLAYING” title, above the list of all tracks (where it also indicate the amount of total tracks in the current playlist”. An active track is marked with a colored right border – depending on the applied theme – this color is matched to the primary color (blue, orange or yellow).

www.7zhao.net

Simply put – Clicking this title will scroll the playlist to the active track (when possible).

www.7zhao.net

Now Playlist Store State

The now playlist state is a rather simple map which includes a list of media tracks, a filter string, a boolean repeat flag and the a string of the active media (selectedId).

内容来自www.7zhao.net

export interface INowPlaylist {
  videos: GoogleApiYouTubeVideoResource[];
  selectedId: string;
  filter: string;
  repeat: boolean;
}
 
const initialState: INowPlaylist = {
  videos: [],
  selectedId: '',
  filter: '',
  repeat: false
};
 

欢迎访问www.7zhao.net

The reveal feature is using the “selectedId” and the list of videos to determine which DOM element it refers to. 去找(www.7zhao.net欢迎您

Now Playing Component

The “Now Playlist ” component is a component of the “Now Playing ” component. The “now-playlist” should get the entire “nowPlaylist” state from the store, as it needs the list of tracks and the selectedId for the reveal feature. copyright www.7zhao.net

BONUS info : The “now-playlist-filter” also gets the “nowPlaylist” state – and so – this is a nice example which shows how these two separate components are operating on the same source of data, and manipulate it (by dispatching actions to the store) accordingly, thus, communicating via this data. 去找(www.7zhao.net欢迎您

@Component({
  selector: 'now-playing',
  styleUrls: ['./now-playing.scss'],
  template: `
  <div class="sidebar-pane">
    <now-playlist-filter
      [ playlist ]="nowPlaylist$ | async"
      (clear)="clearPlaylist()"
      (filter)="updateFilter($event)"
      (reset)="resetFilter()"
      (headerClick)="onHeaderClick()"
    ></now-playlist-filter>
    <now-playlist
      [ playlist ]="nowPlaylist$ | async"
      (select)="selectVideo($event)"
      (selectTrack)="selectTrackInVideo($event)"
      (remove)="removeVideo($event)"
    ></now-playlist>
  </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
 内容来自www.7zhao.net 

The “now playlist” component is responsible for rendering the list of tracks (filtered if there’s any filter), mark the current playing track. It is a presentation component, defined with an “OnPush” strategy for its change detection. copyright www.7zhao.net

The “ scrollToActiveTrack ()” method is responsible for scrolling the container to the currently active track. The activeTrackElement property is a pointer to the active track as a DOM element. This DOM element is saved into this property when the list is rendered. I decided to save a pointer to this element during the the phase where it is rendered – the “ isActiveMedia ()” method is invoked for each track – and it gets the media id and its associated DOM element via an angular template reference achieved with “#playlistTrack”. 本文来自去找www.7zhao.net

@Component({
  selector: 'now-playlist',
  animations: [flyOut],
  encapsulation: ViewEncapsulation.None,
  styleUrls: ['./now-playlist.scss'],
  template: `
  <section class="now-playlist ux-maker">
    <ul class="nav nav-list ux-maker nicer-ux">
      <li class="now-playlist-track" #playlistTrack
        [ngClass]="{
          'active': isActiveMedia(video.id, playlistTrack)
        }"
        *ngFor="let video of playlist.videos | search:playlist.filter; let index = index"
        [@flyOut]>
        <now-playlist-track
          [ video ]="video" 
          [ index ]="index"
          (remove)="removeVideo($event)"
          (select)="selectVideo(video)"
          (selectTrack)="selectTrackInVideo($event)"
        ></now-playlist-track>
      </li>
    </ul>
  </section>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class NowPlaylistComponent implements OnChanges, AfterViewChecked {
  @Input() playlist: NowPlaylist.INowPlaylist;
  @Output() select = new EventEmitter<GoogleApiYouTubeVideoResource>();
  @Output()
  selectTrack = new EventEmitter<{
    time: string;
    media: GoogleApiYouTubeVideoResource;
  }>();
  @Output() remove = new EventEmitter<GoogleApiYouTubeVideoResource>();
 
  public activeTrackElement: HTMLUListElement;
  public hasActiveChanged = false;
 
  constructor(public zone: NgZone) { }
 
  ngAfterViewChecked() {
    if (this.hasActiveChanged && this.activeTrackElement) {
      this.zone.runOutsideAngular(() => this.scrollToActiveTrack());
    }
  }
 
  ngOnChanges({ activeId }: SimpleChanges) {
    if (activeId) {
      this.hasActiveChanged = isNewChange(activeId);
    }
  }
 
  scrollToActiveTrack() {
    if (this.activeTrackElement) {
      this.activeTrackElement.scrollIntoView();
    }
  }
 
  selectVideo(media: GoogleApiYouTubeVideoResource) {
    this.select.emit(media);
  }
 
  removeVideo(media: GoogleApiYouTubeVideoResource) {
    this.remove.emit(media);
  }
 
  isActiveMedia(mediaId: string, trackElement: HTMLUListElement) {
    const isActive = this.playlist.selectedId === mediaId;
    if (isActive) {
      this.activeTrackElement = trackElement;
    }
    return isActive;
  }
 
  selectTrackInVideo(trackEvent: { time; media }) {
    this.selectTrack.emit(trackEvent);
  }
}
 

去找(www.7zhao.net欢迎您

Scrolling To The Active Track

There are 2 possible scenarios where the “scrollToActiveTrack()” method is used.

去找(www.7zhao.net欢迎您

1) AfterViewChecked Component Life Cycle

ngAfterViewChecked() {
    if (this.hasActiveChanged && this.activeTrackElement) {
      this.zone.runOutsideAngular(() => this.scrollToActiveTrack());
    }
  }
 

去找(www.7zhao.net欢迎您

When the active media is changed via the now playlist store, the “ selectedId ” is updated, thus triggering a change detection down to the “now playlist component”, which is the, renders the component and updates the active media in view. 本文来自去找www.7zhao.net

This strategy is mostly useful for an initial render and for the “ selectedId ” is updated within the store. It was also used to trigger a scroll automatically when the next track is activated, however, ux wise, it didn’t feel right and was a little bit annoying – so I decided to disable it for the time being. Nevertheless, it’s a nice example which demonstrates using with auto scrolling dom elements. www.7zhao.net

To optimize performance further, other can be used for initial render only. 本文来自去找www.7zhao.net

2) Using @ViewChild Decorator with Component instance method from parent component

This strategy demonstrates the usage of accessing a component’s public methods, thus manipulating it directly. This can be considered a tightly coupled architecture, however, for the purpose of this feature – it achieves a nice effect easily and can be disabled without affecting the robustness of the app.

欢迎访问www.7zhao.net

This strategy is used inside the “now playing” component. The component queries the “now playlist” component with “ @ViewChild ” decorator, thus, saving a reference to the component’s instance within the “nowPlaylistComponent” property. 去找(www.7zhao.net欢迎您

Now, whenever the “ onHeaderClick ()” method is invoked in response to the “now-playlist-filter” component event, the “ nowPlaylistComponent.scrollToActiveTrack ()” method is invoked directly, scrolling the playlist to the active track element. copyright www.7zhao.net

export class NowPlayingComponent implements OnInit {
  public nowPlaylist$: Observable<INowPlaylist>;
  @ViewChild(NowPlaylistComponent) nowPlaylistComponent: NowPlaylistComponent;
 
  constructor(public store: Store<EchoesState>, public nowPlaylistService: NowPlaylistService) { }
 
  // ...removed code
  onHeaderClick() {
    this.nowPlaylistComponent.scrollToActiveTrack();
  }
}
 
内容来自www.7zhao.net

The benefit of using this strategy is by not triggering any re-render inside the “now-playlist” component – and just using the DOM’s api. 本文来自去找www.7zhao.net

Summary: Putting It All Together

The “ now playing ” feature is a nice component featuring few key concepts that can be achieved with Angular and ngrx: 去找(www.7zhao.net欢迎您

  1. using state management with ngrx
  2. sharing state between components – using the “now playlist” state – sharing the “playlist” and “filter”
  3. communicating between components – using a wrapper component (now playlist)
  4. leveraging  @ViewChild to be able to interact with a component’s public interface, eventually interacting with DOM only api’s

Those concepts can be further enhanced and achieved differently using other strategies. I always look for doingthings simpler or rather different, as long as it feels intuitive, fits thecode architecture used for the app and follow best practices for creating robust code.

内容来自www.7zhao.net

Echoes Player is an open source project and (feel free to fork, open pull requests and suggest features) as well using the actual app at . 本文来自去找www.7zhao.net

If you like this article or in need for an advice for your Front End Development project, reach me out via thecontact page or get a quote free of charge through one ofconsulting packagesi’m offering as part of my services (or click on one of them on the right, if you’re using a desktop/laptop).

copyright www.7zhao.net

copyright www.7zhao.net


本文原文地址:http://orizens.com/wp/topics/ngrx-scrolling-ino-dom-element-and-components-communication/

以上为Ngrx, Scrolling Into DOM Elements & Components Communication文章的全部内容,若您也有好的文章,欢迎与我们分享! 欢迎访问www.7zhao.net

Copyright ©2008-2017去找网版权所有   皖ICP备12002049号-2 皖公网安备 34088102000435号   关于我们|联系我们| 免责声明|友情链接|网站地图|手机版