जब मैं कोणीय 2 में मार्ग बदलता हूं तो मैं लोडिंग स्क्रीन कैसे दिखा सकता हूं?
जब मैं कोणीय 2 में मार्ग बदलता हूं तो मैं लोडिंग स्क्रीन कैसे दिखा सकता हूं?
जवाबों:
वर्तमान कोणीय राउटर नेविगेशन इवेंट प्रदान करता है। आप इनकी सदस्यता ले सकते हैं और तदनुसार UI परिवर्तन कर सकते हैं। याद रखें अन्य घटनाओं में जैसे कि NavigationCancel
और NavigationError
अपने रनर को रोकने के मामले में राउटर संक्रमण विफल हो जाते हैं।
app.component.ts - अपने रूट घटक
...
import {
Router,
// import as RouterEvent to avoid confusion with the DOM Event
Event as RouterEvent,
NavigationStart,
NavigationEnd,
NavigationCancel,
NavigationError
} from '@angular/router'
@Component({})
export class AppComponent {
// Sets initial value to true to show loading spinner on first load
loading = true
constructor(private router: Router) {
this.router.events.subscribe((e : RouterEvent) => {
this.navigationInterceptor(e);
})
}
// Shows and hides the loading spinner during RouterEvent changes
navigationInterceptor(event: RouterEvent): void {
if (event instanceof NavigationStart) {
this.loading = true
}
if (event instanceof NavigationEnd) {
this.loading = false
}
// Set loading state to false in both of the below events to hide the spinner in case a request fails
if (event instanceof NavigationCancel) {
this.loading = false
}
if (event instanceof NavigationError) {
this.loading = false
}
}
}
app.component.html - आपका रूट व्यू
<div class="loading-overlay" *ngIf="loading">
<!-- show something fancy here, here with Angular 2 Material's loading bar or circle -->
<md-progress-bar mode="indeterminate"></md-progress-bar>
</div>
प्रदर्शन में सुधार का जवाब : यदि आप प्रदर्शन के बारे में परवाह करते हैं तो एक बेहतर तरीका है, यह लागू करने के लिए थोड़ा अधिक थकाऊ है लेकिन प्रदर्शन में सुधार अतिरिक्त काम के लायक होगा। इसके बजाय का उपयोग करने का *ngIf
सशर्त स्पिनर को दिखाने के लिए, हम कोणीय का लाभ उठाने सकता है NgZone
और Renderer
पर स्विच / स्पिनर जो कोणीय के परिवर्तन का पता लगाने बाईपास जब हम स्पिनर की राज्य बदल जाएगा बंद। मुझे यह प्रयोग करने *ngIf
या एक async
पाइप की तुलना में एनीमेशन को चिकना बनाने के लिए मिला ।
यह मेरे पिछले उत्तर के समान है, जिसमें कुछ मोड़ हैं:
app.component.ts - अपने रूट घटक
...
import {
Router,
// import as RouterEvent to avoid confusion with the DOM Event
Event as RouterEvent,
NavigationStart,
NavigationEnd,
NavigationCancel,
NavigationError
} from '@angular/router'
import {NgZone, Renderer, ElementRef, ViewChild} from '@angular/core'
@Component({})
export class AppComponent {
// Instead of holding a boolean value for whether the spinner
// should show or not, we store a reference to the spinner element,
// see template snippet below this script
@ViewChild('spinnerElement')
spinnerElement: ElementRef
constructor(private router: Router,
private ngZone: NgZone,
private renderer: Renderer) {
router.events.subscribe(this._navigationInterceptor)
}
// Shows and hides the loading spinner during RouterEvent changes
private _navigationInterceptor(event: RouterEvent): void {
if (event instanceof NavigationStart) {
// We wanna run this function outside of Angular's zone to
// bypass change detection
this.ngZone.runOutsideAngular(() => {
// For simplicity we are going to turn opacity on / off
// you could add/remove a class for more advanced styling
// and enter/leave animation of the spinner
this.renderer.setElementStyle(
this.spinnerElement.nativeElement,
'opacity',
'1'
)
})
}
if (event instanceof NavigationEnd) {
this._hideSpinner()
}
// Set loading state to false in both of the below events to
// hide the spinner in case a request fails
if (event instanceof NavigationCancel) {
this._hideSpinner()
}
if (event instanceof NavigationError) {
this._hideSpinner()
}
}
private _hideSpinner(): void {
// We wanna run this function outside of Angular's zone to
// bypass change detection,
this.ngZone.runOutsideAngular(() => {
// For simplicity we are going to turn opacity on / off
// you could add/remove a class for more advanced styling
// and enter/leave animation of the spinner
this.renderer.setElementStyle(
this.spinnerElement.nativeElement,
'opacity',
'0'
)
})
}
}
app.component.html - आपका रूट व्यू
<div class="loading-overlay" #spinnerElement style="opacity: 0;">
<!-- md-spinner is short for <md-progress-circle mode="indeterminate"></md-progress-circle> -->
<md-spinner></md-spinner>
</div>
router navigation
और it triggering the spinner
और उसके बाद नहीं इसे रोकने के लिए सक्षम किया जा रहा। navigationInterceptor
एक समाधान की तरह लगता है, लेकिन मुझे यकीन नहीं है कि कुछ और टूटने का इंतजार कर रहा है। अगर इसमें मिलावट async requests
फिर से समस्या का परिचय देगी, मुझे लगता है।
display
तो उपयोग करने के लिए बदल दिया none
या inline
।
'md-spinner' is not a known element:
। मैं कोणीय के लिए काफी नया हूं। क्या आप मुझे बता सकते हैं कि क्या गलती हो सकती है?
अद्यतन: 3 अब जब मैंने नए राउटर में अपग्रेड किया है, अगर आप गार्ड का उपयोग करते हैं तो @borislemke का दृष्टिकोण काम नहीं करेगा CanDeactivate
। मैं अपनी पुरानी विधि को नीचा दिखा रहा हूं, ie:
यह जवाब
UPDATE2 : नए-राउटर में राउटर इवेंट आशाजनक दिखते हैं और @borislemke द्वारा उत्तर स्पिनर कार्यान्वयन के मुख्य पहलू को कवर करने के लिए लगता है, मैंने इसका परीक्षण नहीं किया है लेकिन मैं इसकी सलाह देता हूं।
UPDATE1: मैंने यह उत्तर उस युग में लिखा था Old-Router
, जब केवल एक घटना के route-changed
माध्यम से अधिसूचित हुआ करता था router.subscribe()
। मैंने भी नीचे के दृष्टिकोण को अधिभार महसूस किया और केवल इसका उपयोग करने की कोशिश की router.subscribe()
, और यह पता लगाने का कोई रास्ता नहीं होने के कारण बैकफायर हो गया canceled navigation
। इसलिए मुझे लंबे समय तक दृष्टिकोण (दोहरा काम) पर वापस लौटना पड़ा।
यदि आप Angular2 में अपना रास्ता जानते हैं, तो आपको यही चाहिए
Boot.ts
import {bootstrap} from '@angular/platform-browser-dynamic';
import {MyApp} from 'path/to/MyApp-Component';
import { SpinnerService} from 'path/to/spinner-service';
bootstrap(MyApp, [SpinnerService]);
रूट घटक- (MyApp)
import { Component } from '@angular/core';
import { SpinnerComponent} from 'path/to/spinner-component';
@Component({
selector: 'my-app',
directives: [SpinnerComponent],
template: `
<spinner-component></spinner-component>
<router-outlet></router-outlet>
`
})
export class MyApp { }
स्पिनर-घटक (सक्रिय रूप से मूल्य बदलने के लिए स्पिनर-सेवा की सदस्यता लेंगे)
import {Component} from '@angular/core';
import { SpinnerService} from 'path/to/spinner-service';
@Component({
selector: 'spinner-component',
'template': '<div *ngIf="active" class="spinner loading"></div>'
})
export class SpinnerComponent {
public active: boolean;
public constructor(spinner: SpinnerService) {
spinner.status.subscribe((status: boolean) => {
this.active = status;
});
}
}
स्पिनर-सेवा (बूटस्ट्रैप इस सेवा)
परिवर्तन पर स्थिति बदलने के लिए स्पिनर-घटक द्वारा सब्सक्राइब की जाने वाली अवलोकन को परिभाषित करें, और स्पिनर को सक्रिय / निष्क्रिय जानने और सेट करने के लिए कार्य करें।
import {Injectable} from '@angular/core';
import {Subject} from 'rxjs/Subject';
import 'rxjs/add/operator/share';
@Injectable()
export class SpinnerService {
public status: Subject<boolean> = new Subject();
private _active: boolean = false;
public get active(): boolean {
return this._active;
}
public set active(v: boolean) {
this._active = v;
this.status.next(v);
}
public start(): void {
this.active = true;
}
public stop(): void {
this.active = false;
}
}
अन्य सभी मार्गों के अवयव
(नमूना):
import { Component} from '@angular/core';
import { SpinnerService} from 'path/to/spinner-service';
@Component({
template: `<div *ngIf="!spinner.active" id="container">Nothing is Loading Now</div>`
})
export class SampleComponent {
constructor(public spinner: SpinnerService){}
ngOnInit(){
this.spinner.stop(); // or do it on some other event eg: when xmlhttp request completes loading data for the component
}
ngOnDestroy(){
this.spinner.start();
}
}
spinner-service
अभी कुछ कोड जोड़े हैं, आपको इसे काम करने के लिए अन्य भागों की आवश्यकता है। और यह याद रखें किangular2-rc-1
साधारण सीएसएस का उपयोग क्यों न करें:
<router-outlet></router-outlet>
<div class="loading"></div>
और आपकी शैली में:
div.loading{
height: 100px;
background-color: red;
display: none;
}
router-outlet + div.loading{
display: block;
}
या हम पहले उत्तर के लिए भी ऐसा कर सकते हैं:
<router-outlet></router-outlet>
<spinner-component></spinner-component>
और फिर बस
spinner-component{
display:none;
}
router-outlet + spinner-component{
display: block;
}
यहां चाल है, नए मार्गों और घटकों को हमेशा राउटर-आउटलेट के बाद दिखाई देगा , इसलिए एक साधारण सीएसएस चयनकर्ता के साथ हम लोडिंग दिखा सकते हैं और छिपा सकते हैं।
यदि आपके पास पहले मार्ग के लिए विशेष तर्क की आवश्यकता है, तो आप केवल निम्न कार्य कर सकते हैं:
loaded = false;
constructor(private router: Router....) {
router.events.pipe(filter(e => e instanceof NavigationEnd), take(1))
.subscribe((e) => {
this.loaded = true;
alert('loaded - this fires only once');
});
मुझे अपने पृष्ठ पाद लेख को छिपाने के लिए इसकी आवश्यकता थी, जो अन्यथा पृष्ठ के शीर्ष पर दिखाई दे रहा था। इसके अलावा अगर आप केवल पहले पेज के लिए लोडर चाहते हैं तो आप इसका उपयोग कर सकते हैं।
आप इस मौजूदा समाधान का भी उपयोग कर सकते हैं । डेमो यहाँ है । यह यूट्यूब लोडिंग बार की तरह दिखता है। मैंने अभी इसे पाया और इसे अपने प्रोजेक्ट में जोड़ा।