কীভাবে রাউটারউইস স্ট্রেট্যাগি প্রয়োগ করতে হবে অ্যাংুলার 2 এ নির্দিষ্ট রুটের জন্য পাঠানো উচিত


113

আমার একটি কৌণিক 2 মডিউল রয়েছে যাতে আমি রাউটিং বাস্তবায়ন করেছি এবং নেভিগেট করার সময় রাজ্যগুলি সঞ্চিত রাখতে চাই। ব্যবহারকারীর সক্ষম হতে হবে: ১. কোনও সার্চফর্মুলা ব্যবহার করে নথির সন্ধান করুন ২. ফলাফলের মধ্যে একটিতে নেভিগেট করুন ৩. সার্চারসুলেটে ফিরে যান - সার্ভারের সাথে যোগাযোগ না করেই without

এটি রুটরেইজস্ট্রেটিজি সহ সম্ভব। প্রশ্নটি হল: ডকুমেন্টটি সংরক্ষণ করা উচিত নয় আমি কীভাবে এটি প্রয়োগ করব?

সুতরাং রুটের পথ "নথি" এর স্থিতি সংরক্ষণ করা উচিত এবং রুটের পথ "নথি / / আইডি" "রাজ্যটি সংরক্ষণ করা উচিত নয়?

উত্তর:


209

আরে অ্যান্ডারস, দুর্দান্ত প্রশ্ন!

আমি আপনার মতো প্রায় একই ব্যবহারের মামলা পেয়েছি এবং একই জিনিসটি করতে চেয়েছিলাম! ব্যবহারকারী অনুসন্ধান> ফলাফল পান> ফলাফলের জন্য নেভিগেট করে> ব্যবহারকারী নেভিগেট করে> বোম জ্বলজ্বলে ফলাফলগুলিতে দ্রুত ফিরে আসে , তবে আপনি যে নির্দিষ্ট আপনি সংরক্ষণ করতে চান না।

TL; ড

আপনার একটি ক্লাস থাকা দরকার যা RouteReuseStrategyআপনার কৌশল প্রয়োগ করে এবং সরবরাহ করে ngModule। আপনি যদি রুটটি সংরক্ষণ করার সময় সংশোধন করতে চান তবে shouldDetachফাংশনটি সংশোধন করুন । যখন এটি ফিরে আসে true, কৌণিকটি রুটটি সঞ্চয় করে। রুটটি সংযুক্ত হওয়ার পরে আপনি যদি সংশোধন করতে চান তবে shouldAttachফাংশনটি সংশোধন করুন । যখন shouldAttachসত্য ফেরৎ, কৌণিক অনুরোধ রুটের জায়গায় সঞ্চিত রুট ব্যবহার করবে। আপনার সাথে খেলা করার জন্য এখানে একটি প্লাঙ্কার

রাউটারউইজ স্ট্রেটজি সম্পর্কে

এই প্রশ্নটি জিজ্ঞাসা করে, আপনি ইতিমধ্যে বুঝতে পেরেছেন যে রাউটারউইজস্ট্রেজি আপনাকে কৌনিকটিকে কোনও উপাদান নষ্ট না করতে বলার অনুমতি দেয় তবে বাস্তবে এটি পরবর্তী তারিখে পুনরায় রেন্ডারিংয়ের জন্য সংরক্ষণ করতে পারে। এটি দুর্দান্ত কারণ এটি অনুমতি দেয়:

  • হ্রাস সার্ভার কল
  • গতি বেড়েছে
  • এবং উপাদানটি রেন্ডার করে, ডিফল্টরূপে, একই অবস্থায় এটি বাকী ছিল

এটি সর্বশেষটি গুরুত্বপূর্ণ যদি আপনি বলতে চান যে, কোনও পৃষ্ঠা অস্থায়ীভাবে ছেড়ে দিন যদিও ব্যবহারকারী এতে প্রচুর পাঠ্য সন্নিবেশ করেছেন। অতিরিক্ত পরিমাণের ফর্মের কারণে এন্টারপ্রাইজ অ্যাপ্লিকেশনগুলি এই বৈশিষ্ট্যটি পছন্দ করবে !

এই সমস্যাটি সমাধান করার জন্যই আমি এনেছি। যেমনটি আপনি বলেছেন, আপনার ব্যবহার করা দরকারRouteReuseStrategy @ কৌনিক / রাউটার দ্বারা প্রস্তাবিত 3.4.1 সংস্করণ এবং উচ্চতরগুলিতে ।

করতে

প্রথম আপনার প্রকল্পের @ কৌনিক / রাউটার সংস্করণ 3.4.1 বা তার বেশি রয়েছে তা নিশ্চিত করুন।

পরবর্তী , যা আপনার বর্গ কার্যকরী ঐ বাড়িতে হবে যারা একটি ফাইল তৈরি RouteReuseStrategy। আমি আমার নামক reuse-strategy.tsএবং এটি স্থাপন /appজিম্মা জন্য ফোল্ডার। আপাতত, এই শ্রেণীর মতো হওয়া উচিত:

import { RouteReuseStrategy } from '@angular/router';

export class CustomReuseStrategy implements RouteReuseStrategy {
}

(আপনার টাইপস্ক্রিপ্ট ত্রুটি সম্পর্কে চিন্তা করবেন না, আমরা সবকিছু সমাধান করতে চলেছি)

আপনার ক্লাসটি সরবরাহ করে ভিত্তি শেষ করুন app.module। নোট করুন যে আপনি এখনও লিখেন নি CustomReuseStrategy, তবে এগিয়ে যাওয়া উচিত এবং importএটি reuse-strategy.tsসমস্ত একইরকম। এছাড়াওimport { RouteReuseStrategy } from '@angular/router';

@NgModule({
    [...],
    providers: [
        {provide: RouteReuseStrategy, useClass: CustomReuseStrategy}
    ]
)}
export class AppModule {
}

চূড়ান্ত টুকরাটি ক্লাসটি লিখছে যা রুটগুলি বিচ্ছিন্ন, সংরক্ষণ, পুনরুদ্ধার এবং পুনরায় সংযুক্ত হবে কিনা তা নিয়ন্ত্রণ করবে। আমরা পুরানো অনুলিপি / পেস্টে পৌঁছানোর আগে আমি এখানে যান্ত্রিকগুলির একটি সংক্ষিপ্ত ব্যাখ্যা করব, যেমন আমি তাদের বুঝি। আমি যে পদ্ধতিগুলি বর্ণনা করছি তার জন্য নীচের কোডটি উল্লেখ করুন এবং অবশ্যই কোডটিতে প্রচুর ডকুমেন্টেশন রয়েছে

  1. আপনি নেভিগেট যখন, shouldReuseRouteঅগ্নি। এটি আমার কাছে কিছুটা অদ্ভুত, তবে যদি এটি ফিরে আসেtrue তবে এটি বর্তমানে আপনি যে রুটে রয়েছেন তা পুনরায় ব্যবহার করে এবং অন্য কোনও পদ্ধতিতে বরখাস্ত হয় না। যদি ব্যবহারকারী দূরে নেভিগেট করে থাকে তবে আমি মিথ্যা ফিরিয়ে দেব।
  2. তাহলে shouldReuseRouteআয় false, shouldDetachদাবানল। shouldDetachআপনি রুটটি সঞ্চয় করতে চান কিনা তা নির্ধারণ করে এবং booleanযতটা ইঙ্গিত দেয় তা দেয়। এখানেই আপনার পাথগুলি সংরক্ষণ / না সঞ্চয় করার সিদ্ধান্ত নেওয়া উচিত যা আমি আপনি যে পথগুলির বিরুদ্ধে সঞ্চয় করতে চান তার একটি অ্যারে পরীক্ষা করে route.routeConfig.pathএবং যদি pathঅ্যারেটিতে উপস্থিত না থাকে তবে মিথ্যা ফিরিয়ে নেওয়া উচিত।
  3. যদি shouldDetachফেরত আসে true, storeতা বরখাস্ত করা হয়, যা রুট সম্পর্কে আপনি যে তথ্য চান তা আপনার কাছে সঞ্চয় করার জন্য একটি সুযোগ। আপনি যাই করুন না কেন, আপনার সংরক্ষণ করতে হবে DetachedRouteHandleকারণ এটি পরে আপনার সঞ্চিত উপাদান সনাক্ত করতে কৌণিক ব্যবহার করে। নীচে, আমি DetachedRouteHandleএবং ActivatedRouteSnapshotআমার ক্লাসে একটি ভেরিয়েবল স্থানীয়তে উভয়ই সঞ্চয় করি ।

সুতরাং, আমরা সঞ্চয়ের জন্য যুক্তিবিজ্ঞান, কিন্তু কি নেভিগেট সম্পর্কে দেখা করেছি থেকে একটি উপাদান? অ্যাঙ্গুলার কীভাবে আপনার ন্যাভিগেশনকে বাধা দেবে এবং সঞ্চিতটিকে তার জায়গায় রাখবে?

  1. আবার, shouldReuseRouteফিরে আসার পরে false, shouldAttachরান করে, যা আপনি মেমোরিতে উপাদানটি পুনরায় জেনারেট করতে বা ব্যবহার করতে চান কিনা তা বের করার সুযোগ। আপনি যদি কোনও সঞ্চিত উপাদান পুনরায় ব্যবহার করতে চান তবে ফিরে আসুনtrue এবং আপনি ভাল আছেন!
  2. এখন কৌণিক আপনাকে জিজ্ঞাসা করবে, "আপনি কোন উপাদানটি আমাদের ব্যবহার করতে চান?", যা আপনি সেই উপাদানটির DetachedRouteHandleমধ্য থেকে ফিরে এসে চিহ্নিত করতে পারবেন retrieve

এটি আপনার প্রয়োজন সমস্ত যুক্তিযুক্ত সুন্দর! নীচের কোডে reuse-strategy.ts, আমি আপনাকে একটি নিফটি ফাংশনও রেখেছি যা দুটি বস্তুর তুলনা করবে। আমি এটি ব্যবহার করে ভবিষ্যতের রুটের route.paramsএবং route.queryParamsসঞ্চিত রুটের সাথে তুলনা করতে। যদি এই সমস্তগুলি মিলে যায় তবে আমি একটি নতুন তৈরির পরিবর্তে সঞ্চিত উপাদানটি ব্যবহার করতে চাই। তবে আপনি কীভাবে এটি করবেন তা আপনার উপর নির্ভর করে!

পুনঃব্যবহারের-strategy.ts

/**
 * reuse-strategy.ts
 * by corbfon 1/6/17
 */

import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle } from '@angular/router';

/** Interface for object which can store both: 
 * An ActivatedRouteSnapshot, which is useful for determining whether or not you should attach a route (see this.shouldAttach)
 * A DetachedRouteHandle, which is offered up by this.retrieve, in the case that you do want to attach the stored route
 */
interface RouteStorageObject {
    snapshot: ActivatedRouteSnapshot;
    handle: DetachedRouteHandle;
}

export class CustomReuseStrategy implements RouteReuseStrategy {

    /** 
     * Object which will store RouteStorageObjects indexed by keys
     * The keys will all be a path (as in route.routeConfig.path)
     * This allows us to see if we've got a route stored for the requested path
     */
    storedRoutes: { [key: string]: RouteStorageObject } = {};

    /** 
     * Decides when the route should be stored
     * If the route should be stored, I believe the boolean is indicating to a controller whether or not to fire this.store
     * _When_ it is called though does not particularly matter, just know that this determines whether or not we store the route
     * An idea of what to do here: check the route.routeConfig.path to see if it is a path you would like to store
     * @param route This is, at least as I understand it, the route that the user is currently on, and we would like to know if we want to store it
     * @returns boolean indicating that we want to (true) or do not want to (false) store that route
     */
    shouldDetach(route: ActivatedRouteSnapshot): boolean {
        let detach: boolean = true;
        console.log("detaching", route, "return: ", detach);
        return detach;
    }

    /**
     * Constructs object of type `RouteStorageObject` to store, and then stores it for later attachment
     * @param route This is stored for later comparison to requested routes, see `this.shouldAttach`
     * @param handle Later to be retrieved by this.retrieve, and offered up to whatever controller is using this class
     */
    store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
        let storedRoute: RouteStorageObject = {
            snapshot: route,
            handle: handle
        };

        console.log( "store:", storedRoute, "into: ", this.storedRoutes );
        // routes are stored by path - the key is the path name, and the handle is stored under it so that you can only ever have one object stored for a single path
        this.storedRoutes[route.routeConfig.path] = storedRoute;
    }

    /**
     * Determines whether or not there is a stored route and, if there is, whether or not it should be rendered in place of requested route
     * @param route The route the user requested
     * @returns boolean indicating whether or not to render the stored route
     */
    shouldAttach(route: ActivatedRouteSnapshot): boolean {

        // this will be true if the route has been stored before
        let canAttach: boolean = !!route.routeConfig && !!this.storedRoutes[route.routeConfig.path];

        // this decides whether the route already stored should be rendered in place of the requested route, and is the return value
        // at this point we already know that the paths match because the storedResults key is the route.routeConfig.path
        // so, if the route.params and route.queryParams also match, then we should reuse the component
        if (canAttach) {
            let willAttach: boolean = true;
            console.log("param comparison:");
            console.log(this.compareObjects(route.params, this.storedRoutes[route.routeConfig.path].snapshot.params));
            console.log("query param comparison");
            console.log(this.compareObjects(route.queryParams, this.storedRoutes[route.routeConfig.path].snapshot.queryParams));

            let paramsMatch: boolean = this.compareObjects(route.params, this.storedRoutes[route.routeConfig.path].snapshot.params);
            let queryParamsMatch: boolean = this.compareObjects(route.queryParams, this.storedRoutes[route.routeConfig.path].snapshot.queryParams);

            console.log("deciding to attach...", route, "does it match?", this.storedRoutes[route.routeConfig.path].snapshot, "return: ", paramsMatch && queryParamsMatch);
            return paramsMatch && queryParamsMatch;
        } else {
            return false;
        }
    }

    /** 
     * Finds the locally stored instance of the requested route, if it exists, and returns it
     * @param route New route the user has requested
     * @returns DetachedRouteHandle object which can be used to render the component
     */
    retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {

        // return null if the path does not have a routerConfig OR if there is no stored route for that routerConfig
        if (!route.routeConfig || !this.storedRoutes[route.routeConfig.path]) return null;
        console.log("retrieving", "return: ", this.storedRoutes[route.routeConfig.path]);

        /** returns handle when the route.routeConfig.path is already stored */
        return this.storedRoutes[route.routeConfig.path].handle;
    }

    /** 
     * Determines whether or not the current route should be reused
     * @param future The route the user is going to, as triggered by the router
     * @param curr The route the user is currently on
     * @returns boolean basically indicating true if the user intends to leave the current route
     */
    shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
        console.log("deciding to reuse", "future", future.routeConfig, "current", curr.routeConfig, "return: ", future.routeConfig === curr.routeConfig);
        return future.routeConfig === curr.routeConfig;
    }

    /** 
     * This nasty bugger finds out whether the objects are _traditionally_ equal to each other, like you might assume someone else would have put this function in vanilla JS already
     * One thing to note is that it uses coercive comparison (==) on properties which both objects have, not strict comparison (===)
     * Another important note is that the method only tells you if `compare` has all equal parameters to `base`, not the other way around
     * @param base The base object which you would like to compare another object to
     * @param compare The object to compare to base
     * @returns boolean indicating whether or not the objects have all the same properties and those properties are ==
     */
    private compareObjects(base: any, compare: any): boolean {

        // loop through all properties in base object
        for (let baseProperty in base) {

            // determine if comparrison object has that property, if not: return false
            if (compare.hasOwnProperty(baseProperty)) {
                switch(typeof base[baseProperty]) {
                    // if one is object and other is not: return false
                    // if they are both objects, recursively call this comparison function
                    case 'object':
                        if ( typeof compare[baseProperty] !== 'object' || !this.compareObjects(base[baseProperty], compare[baseProperty]) ) { return false; } break;
                    // if one is function and other is not: return false
                    // if both are functions, compare function.toString() results
                    case 'function':
                        if ( typeof compare[baseProperty] !== 'function' || base[baseProperty].toString() !== compare[baseProperty].toString() ) { return false; } break;
                    // otherwise, see if they are equal using coercive comparison
                    default:
                        if ( base[baseProperty] != compare[baseProperty] ) { return false; }
                }
            } else {
                return false;
            }
        }

        // returns true only after false HAS NOT BEEN returned through all loops
        return true;
    }
}

আচরণ

এই বাস্তবায়নটি প্রতিটি অনন্য রুটকে সংরক্ষণ করে যা ব্যবহারকারী রাউটারে ঠিক একবারে দেখেছেন। এটি সাইটে ব্যবহারকারীর অধিবেশন জুড়ে স্মৃতিতে সঞ্চিত উপাদানগুলিতে যোগ করা চালিয়ে যাবে। আপনি যদি সংরক্ষণ করেন এমন রুটগুলি সীমাবদ্ধ করতে চান তবে এটি করার জায়গাটি হ'ল shouldDetachপদ্ধতি। আপনি কোন রুটগুলি সংরক্ষণ করবেন তা এটি নিয়ন্ত্রণ করে।

উদাহরণ

বলুন আপনার ব্যবহারকারী হোমপৃষ্ঠা থেকে এমন কিছু সন্ধান করেছেন, যা এটিকে পথে চালিত করে search/:term, যা প্রদর্শিত হতে পারে www.yourwebsite.com/search/thingsearchedfor। অনুসন্ধান পৃষ্ঠায় অনুসন্ধান ফলাফলগুলির একটি গুচ্ছ রয়েছে contains আপনি যদি এই পথে ফিরে আসতে চান তবে আপনি এই রুটটি সংরক্ষণ করতে চান! এখন তারা একটি অনুসন্ধান ফলাফলকে ক্লিক করে নেভিগেট হয়ে যায় view/:resultId, যা আপনি সংরক্ষণ করতে চান না , তারা সম্ভবত একবারেই সেখানে আসবে তা দেখে। উপরোক্ত বাস্তবায়নের জায়গায়, আমি কেবল shouldDetachপদ্ধতিটি পরিবর্তন করব ! এটি দেখতে কেমন লাগবে তা এখানে:

প্রথমে আসুন আমরা যে পাথগুলি সঞ্চয় করতে চাই তার একটি অ্যারে তৈরি করি।

private acceptedRoutes: string[] = ["search/:term"];

এখন, shouldDetachআমরা route.routeConfig.pathআমাদের অ্যারের বিরুদ্ধে পরীক্ষা করতে পারি ।

shouldDetach(route: ActivatedRouteSnapshot): boolean {
    // check to see if the route's path is in our acceptedRoutes array
    if (this.acceptedRoutes.indexOf(route.routeConfig.path) > -1) {
        console.log("detaching", route);
        return true;
    } else {
        return false; // will be "view/:resultId" when user navigates to result
    }
}

যেহেতু কৌণিক কেবল একটি রুটের একটি উদাহরণ সংরক্ষণ করবে, এই সঞ্চয়স্থানটি হালকা ওজনের হবে এবং আমরা কেবল সেখানে থাকা উপাদানটি সংরক্ষণ করব search/:termএবং অন্য সকলকে নয়!

অতিরিক্ত লিঙ্ক

যদিও এখনও সেখানে খুব বেশি ডকুমেন্টেশন নেই, তবে এখানে যা আছে তার সাথে কয়েকটি লিঙ্ক রয়েছে:

কৌণিক ডকস: https://angular.io/docs/ts/latest/api/router/index/RouteReuseStrategy-class.html

ইন্ট্রো প্রবন্ধ: https://www.softwarearchitekt.at/post/2016/12/02/sticky-routes-in-angular-2-3-with-routereusestrategy.aspx

নেটিসস্ক্রিপ্ট-কৌণিকের ডিফল্ট রাউটারউজস্ট্রেটির বাস্তবায়ন : https://github.com/NativeScript/nativescript-angular/blob/cb4fd3a/nativescript-angular/router/ns-route-reuse-strategy.ts


2
@ শাহীন আমি একটি উদাহরণ যুক্ত করেছি, এটি আমার বর্তমান বাস্তবায়নের মধ্যে সঠিক কোডটি!
কর্বফন

1
@ কর্বফন আমি সরকারী গিথুব
Tjaart van der Walt

2
কোনও সঞ্চিত রুটটিকে পুনরায় সক্রিয় করার সময় এনিমেশনগুলি পুনরায় চালিত করার কোনও উপায় আছে কি?
জিন্দার সিধু

2
ReuseRouteStrategy আপনার উপাদানটি রাউটারের কাছে ফিরিয়ে দেবে, সুতরাং এটি যে অবস্থায় থাকবে তা সেখানে থাকবে you' আপনি যদি সংযুক্তিটির জন্য উপাদান (গুলি) প্রতিক্রিয়া দেখাতে চান তবে আপনি একটি পরিষেবা ব্যবহার করতে পারেন যা একটি প্রস্তাব করে Observable। উপাদানটি লাইফসাইকেল হুকের Observableসময় সাবস্ক্রাইব করা উচিত ngOnInit। তারপরে আপনি কম্পোনেন্টটি বলতে পারবেন, এটি থেকে ReuseRouteStrategy, এটি সবেমাত্র সংযুক্ত হয়েছে এবং উপাদানটি তার রাজ্যটিকে ফিট হিসাবে পরিবর্তন করতে পারে।
কর্ফন

1
@ অ্যান্ডারসগ্রামমাইগাইন্ড যদি আমার উত্তর আপনার প্রস্তাবিত প্রশ্নের উত্তর সরবরাহ করে তবে আপনি কি উত্তর হিসাবে চিহ্নিত করবেন?
কর্বফন

44

গৃহীত উত্তরে ভয় পাবেন না, এটি বেশ সোজা। আপনার যা প্রয়োজন তা এখানে একটি দ্রুত উত্তর। আমি কমপক্ষে স্বীকৃত উত্তরটি পড়ার সুপারিশ করব, কারণ এটি দুর্দান্ত বিবরণে পূর্ণ।

এই সমাধানটি গৃহীত উত্তরের মতো কোনও প্যারামিটার তুলনা করে না তবে এটি কয়েকটি সেট রুট সংরক্ষণের জন্য ভাল কাজ করবে।

app.module.ts আমদানি:

import { RouteReuseStrategy } from '@angular/router';
import { CustomReuseStrategy, Routing } from './shared/routing';

@NgModule({
//...
providers: [
    { provide: RouteReuseStrategy, useClass: CustomReuseStrategy },
  ]})

শেয়ারকৃত / routing.ts:

export class CustomReuseStrategy implements RouteReuseStrategy {
 routesToCache: string[] = ["dashboard"];
 storedRouteHandles = new Map<string, DetachedRouteHandle>();

 // Decides if the route should be stored
 shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return this.routesToCache.indexOf(route.routeConfig.path) > -1;
 }

 //Store the information for the route we're destructing
 store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    this.storedRouteHandles.set(route.routeConfig.path, handle);
 }

//Return true if we have a stored route object for the next route
 shouldAttach(route: ActivatedRouteSnapshot): boolean {
    return this.storedRouteHandles.has(route.routeConfig.path);
 }

 //If we returned true in shouldAttach(), now return the actual route data for restoration
 retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
    return this.storedRouteHandles.get(route.routeConfig.path);
 }

 //Reuse the route if we're going to and from the same route
 shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return future.routeConfig === curr.routeConfig;
 }
}

1
এটি কি অলস বোঝাযুক্ত রুটগুলির জন্যও কাজ করবে?
ব্লুপর্ল

নীচে @ ব্লুপ্রল চেক উত্তর দেখুন
ক্রিস ফ্রেমজেন

2
রুটকনফিগ বিভিন্ন রুটের জন্য নাল, তাই রিউজরউটে সর্বদা সত্য প্রত্যাবর্তন করবে যা কাঙ্ক্ষিত আচরণ নয়
গিল এপশেটেন

19

গৃহীত উত্তর (কর্বফোন দ্বারা) এবং ক্রিস ফ্রেমজেনের সংক্ষিপ্ত এবং আরও সহজ ব্যাখ্যা ছাড়াও, আমি পুনরায় ব্যবহারের কৌশলটি ব্যবহার করা উচিত এমন রুটগুলি পরিচালনা করার আরও নমনীয় উপায় যুক্ত করতে চাই।

উভয় উত্তরই যে রুটগুলিকে আমরা অ্যারেতে ক্যাশে রাখতে চাইছি তা সংরক্ষণ করে এবং তারপরে বর্তমান রুটের পথটি অ্যারেতে রয়েছে কিনা তা পরীক্ষা করে দেখুন। এই চেকটি shouldDetachপদ্ধতিতে করা হয়।

আমি এই পদ্ধতিকে অবিচ্ছেদ্য বলে মনে করি কারণ আমরা যদি আমাদের রুটের নাম পরিবর্তন করতে চাই তবে আমাদের CustomReuseStrategyক্লাসের রুটের নামও পরিবর্তন করতে হবে । আমরা হয় এটি পরিবর্তন করতে ভুলে যেতে পারি বা আমাদের দলের অন্য কোনও বিকাশকারী এমনকি অস্তিত্ব সম্পর্কে না জেনেও রুটের নাম পরিবর্তন করার সিদ্ধান্ত নিতে পারেন RouteReuseStrategy

অ্যারেতে আমরা যে রুটগুলি ক্যাশে করতে চাইছি তা সংরক্ষণ করার পরিবর্তে আমরা তাদের সরাসরি বস্তু RouterModuleব্যবহার করে চিহ্নিত করতে পারি data। এইভাবে আমরা রুটের নাম পরিবর্তন করলেও, পুনরায় ব্যবহারের কৌশলটি প্রয়োগ করা হবে।

{
  path: 'route-name-i-can-change',
  component: TestComponent,
  data: {
    reuseRoute: true
  }
}

এবং তারপরে shouldDetachপদ্ধতিতে আমরা এটি ব্যবহার করি।

shouldDetach(route: ActivatedRouteSnapshot): boolean {
  return route.data.reuseRoute === true;
}

1
ভাল সমাধান। এটি প্রয়োগ করার মতো একটি সাধারণ পতাকা দিয়ে সত্যিই কেবল স্ট্যান্ডার্ড কৌণিক রুট পুনরায় ব্যবহারের কৌশলটিতে বেক করা উচিত।
এমআইপি 1983

দুর্দান্ত উত্তর। আপনাকে অনেক ধন্যবাদ!
ক্লোদিওমাটিআসর্গ

14

অলসভাবে লোড হওয়া মডিউলগুলির সাথে ক্রিস ফ্রেমজেনের কৌশলটি ব্যবহার করতে, কাস্টমরেজস্ট্রেজি ক্লাসটি নিম্নলিখিতটিতে সংশোধন করুন:

import {ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy} from '@angular/router';

export class CustomReuseStrategy implements RouteReuseStrategy {
  routesToCache: string[] = ["company"];
  storedRouteHandles = new Map<string, DetachedRouteHandle>();

  // Decides if the route should be stored
  shouldDetach(route: ActivatedRouteSnapshot): boolean {
     return this.routesToCache.indexOf(route.data["key"]) > -1;
  }

  //Store the information for the route we're destructing
  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
     this.storedRouteHandles.set(route.data["key"], handle);
  }

  //Return true if we have a stored route object for the next route
  shouldAttach(route: ActivatedRouteSnapshot): boolean {
     return this.storedRouteHandles.has(route.data["key"]);
  }

  //If we returned true in shouldAttach(), now return the actual route data for restoration
  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
     return this.storedRouteHandles.get(route.data["key"]);
  }

  //Reuse the route if we're going to and from the same route
  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
     return future.routeConfig === curr.routeConfig;
  }
}

অবশেষে, আপনার বৈশিষ্ট্য মডিউলগুলির রাউটিং ফাইলগুলিতে, আপনার কীগুলি সংজ্ঞায়িত করুন:

{ path: '', component: CompanyComponent, children: [
    {path: '', component: CompanyListComponent, data: {key: "company"}},
    {path: ':companyID', component: CompanyDetailComponent},
]}

আরও তথ্য এখানে


1
এটি যুক্ত করার জন্য ধন্যবাদ! আমি চেষ্টা করে দেখেছি এমনকি আমার সমাধানের মধ্যে চালিত কয়েকটি শিশু রুট পরিচালনা করার সমস্যাগুলিও এটি ঠিক করতে পারে।
কর্বফোন

route.data["key"]ত্রুটি ছাড়াই আমাকে নির্মাণ করতে হয়েছিল use তবে আমি যে সমস্যাটি করছি তা হ'ল আমার কাছে একটি রুট + উপাদান রয়েছে যা দুটি পৃথক স্থানে ব্যবহৃত হয়। 1. sample/list/itemএবং 2. product/id/sample/list/itemআমি যখন প্রথম কোনও পাথ লোড করি তখন এটি সূক্ষ্মভাবে লোড হয় তবে অন্যটি পুনরায় যুক্ত ত্রুটি নিক্ষেপ করে কারণ আমি ভিত্তিতে সংরক্ষণ করছি list/itemতাই আমার প্রায় কাজটিই আমি রুটটিকে অনুলিপি করেছিলাম এবং ইউআরএল পথে কিছু পরিবর্তন করেছি তবে একই উপাদানটি প্রদর্শন করছি। এটির জন্য অন্য কোনও কাজ আছে কিনা তা নিশ্চিত নয়।
ব্লুপর্ল

এই ধরণের আমাকে বিভ্রান্ত করেছে, উপরেরটি ঠিক কাজ করবে না, আমি আমার ক্যাশে রুটের একটিটিকে আঘাত করার সাথে সাথে এটি উড়ে যাবে, (এটি আর নেভিগেট করবে না এবং সেখানে কনসোলে ত্রুটি রয়েছে)। ক্রিস ফ্রেমজেনের সমাধানটি আমার অলস মডিউলগুলির সাথে যথাসম্ভব আমি এতদূর বলতে পারছি বলে মনে হচ্ছে ...
MIP1983

11

আর একটি বাস্তবায়ন আরও বৈধ, সম্পূর্ণ এবং পুনরায় ব্যবহারযোগ্য। এই একটি অলস লোডযুক্ত মডিউলগুলিকে @ উওর দিনç হিসাবে সমর্থন করে এবং @ পছন্দ রুটের ডেটা পতাকাকে সংহত করে। সেরা উন্নতি হ'ল পৃষ্ঠা পরম পথের উপর ভিত্তি করে (প্রায়) অনন্য শনাক্তকারীর স্বয়ংক্রিয় প্রজন্ম। এইভাবে আপনাকে প্রতিটি পৃষ্ঠায় এটি নিজেকে সংজ্ঞায়িত করতে হবে না।

আপনি সেটিংস ক্যাশে করতে চান এমন কোনও পৃষ্ঠা চিহ্নিত করুন reuseRoute: true। এটি shouldDetachপদ্ধতিতে ব্যবহৃত হবে ।

{
  path: '',
  component: MyPageComponent,
  data: { reuseRoute: true },
}

কোয়েরি প্যারামগুলির তুলনা না করেই এটি সহজ কৌশল বাস্তবায়ন।

import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle, UrlSegment } from '@angular/router'

export class CustomReuseStrategy implements RouteReuseStrategy {

  storedHandles: { [key: string]: DetachedRouteHandle } = {};

  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return route.data.reuseRoute || false;
  }

  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    const id = this.createIdentifier(route);
    if (route.data.reuseRoute) {
      this.storedHandles[id] = handle;
    }
  }

  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    const id = this.createIdentifier(route);
    const handle = this.storedHandles[id];
    const canAttach = !!route.routeConfig && !!handle;
    return canAttach;
  }

  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
    const id = this.createIdentifier(route);
    if (!route.routeConfig || !this.storedHandles[id]) return null;
    return this.storedHandles[id];
  }

  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return future.routeConfig === curr.routeConfig;
  }

  private createIdentifier(route: ActivatedRouteSnapshot) {
    // Build the complete path from the root to the input route
    const segments: UrlSegment[][] = route.pathFromRoot.map(r => r.url);
    const subpaths = ([] as UrlSegment[]).concat(...segments).map(segment => segment.path);
    // Result: ${route_depth}-${path}
    return segments.length + '-' + subpaths.join('/');
  }
}

এটিও ক্যোয়ারী প্যারামগুলির সাথে তুলনা করে। compareObjects@ কর্বফোন সংস্করণটির তুলনায় কিছুটা উন্নতি হয়েছে: উভয় বেসের বৈশিষ্ট্যগুলির সাথে লুপ করুন এবং বস্তুর তুলনা করুন। মনে রাখবেন যে আপনি লোডাশ isEqualপদ্ধতির মতো একটি বাহ্যিক এবং আরও নির্ভরযোগ্য বাস্তবায়ন ব্যবহার করতে পারেন ।

import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle, UrlSegment } from '@angular/router'

interface RouteStorageObject {
  snapshot: ActivatedRouteSnapshot;
  handle: DetachedRouteHandle;
}

export class CustomReuseStrategy implements RouteReuseStrategy {

  storedRoutes: { [key: string]: RouteStorageObject } = {};

  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return route.data.reuseRoute || false;
  }

  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    const id = this.createIdentifier(route);
    if (route.data.reuseRoute && id.length > 0) {
      this.storedRoutes[id] = { handle, snapshot: route };
    }
  }

  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    const id = this.createIdentifier(route);
    const storedObject = this.storedRoutes[id];
    const canAttach = !!route.routeConfig && !!storedObject;
    if (!canAttach) return false;

    const paramsMatch = this.compareObjects(route.params, storedObject.snapshot.params);
    const queryParamsMatch = this.compareObjects(route.queryParams, storedObject.snapshot.queryParams);

    console.log('deciding to attach...', route, 'does it match?');
    console.log('param comparison:', paramsMatch);
    console.log('query param comparison', queryParamsMatch);
    console.log(storedObject.snapshot, 'return: ', paramsMatch && queryParamsMatch);

    return paramsMatch && queryParamsMatch;
  }

  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
    const id = this.createIdentifier(route);
    if (!route.routeConfig || !this.storedRoutes[id]) return null;
    return this.storedRoutes[id].handle;
  }

  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return future.routeConfig === curr.routeConfig;
  }

  private createIdentifier(route: ActivatedRouteSnapshot) {
    // Build the complete path from the root to the input route
    const segments: UrlSegment[][] = route.pathFromRoot.map(r => r.url);
    const subpaths = ([] as UrlSegment[]).concat(...segments).map(segment => segment.path);
    // Result: ${route_depth}-${path}
    return segments.length + '-' + subpaths.join('/');
  }

  private compareObjects(base: any, compare: any): boolean {

    // loop through all properties
    for (const baseProperty in { ...base, ...compare }) {

      // determine if comparrison object has that property, if not: return false
      if (compare.hasOwnProperty(baseProperty)) {
        switch (typeof base[baseProperty]) {
          // if one is object and other is not: return false
          // if they are both objects, recursively call this comparison function
          case 'object':
            if (typeof compare[baseProperty] !== 'object' || !this.compareObjects(base[baseProperty], compare[baseProperty])) {
              return false;
            }
            break;
          // if one is function and other is not: return false
          // if both are functions, compare function.toString() results
          case 'function':
            if (typeof compare[baseProperty] !== 'function' || base[baseProperty].toString() !== compare[baseProperty].toString()) {
              return false;
            }
            break;
          // otherwise, see if they are equal using coercive comparison
          default:
            // tslint:disable-next-line triple-equals
            if (base[baseProperty] != compare[baseProperty]) {
              return false;
            }
        }
      } else {
        return false;
      }
    }

    // returns true only after false HAS NOT BEEN returned through all loops
    return true;
  }
}

যদি আপনার অনন্য কী উত্পন্ন করার সর্বোত্তম উপায় থাকে তবে আমার উত্তরটিতে মন্তব্য করুন, আমি কোডটি আপডেট করব।

যারা তাদের সমাধান ভাগ করে নিয়েছেন তাদের সকলকে ধন্যবাদ।


3
এটি গ্রহণযোগ্য উত্তর হওয়া উচিত। উপরে প্রদত্ত অনেকগুলি সমাধান একই সন্তানের URL সহ একাধিক পৃষ্ঠাগুলি সমর্থন করতে পারে না। কারণ তারা সক্রিয় রুট ইউআরএলকে তুলনা করছে যা পুরো পথ নয়।
zhuhang.jasper

4

উল্লিখিত সমস্ত সমাধান আমাদের ক্ষেত্রে কোনওভাবেই অপর্যাপ্ত ছিল। আমাদের সাথে আরও ছোট ব্যবসায়িক অ্যাপ রয়েছে:

  1. ভূমিকা পৃষ্ঠা
  2. লগইন পৃষ্ঠায়
  3. অ্যাপ (লগইনের পরে)

আমাদের প্রয়োজনীয়তা:

  1. অলস-বোঝা মডিউল
  2. মাল্টি-লেভেল রুট
  3. অ্যাপ বিভাগে মেমরিতে সমস্ত রাউটার / উপাদান স্টেটগুলি সঞ্চয় করুন
  4. নির্দিষ্ট রুটে ডিফল্ট কৌণিক পুনরায় ব্যবহারের কৌশল ব্যবহারের বিকল্প
  5. লগআউটে মেমরিতে থাকা সমস্ত উপাদান ধ্বংস করা হচ্ছে

আমাদের রুটের সরলীকৃত উদাহরণ:

const routes: Routes = [{
    path: '',
    children: [
        {
            path: '',
            canActivate: [CanActivate],
            loadChildren: () => import('./modules/dashboard/dashboard.module').then(module => module.DashboardModule)
        },
        {
            path: 'companies',
            canActivate: [CanActivate],
            loadChildren: () => import('./modules/company/company.module').then(module => module.CompanyModule)
        }
    ]
},
{
    path: 'login',
    loadChildren: () => import('./modules/login/login.module').then(module => module.LoginModule),
    data: {
        defaultReuseStrategy: true, // Ignore our custom route strategy
        resetReuseStrategy: true // Logout redirect user to login and all data are destroyed
    }
}];

কৌশল পুনরায় ব্যবহার করুন:

export class AppReuseStrategy implements RouteReuseStrategy {

private handles: Map<string, DetachedRouteHandle> = new Map();

// Asks if a snapshot from the current routing can be used for the future routing.
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return future.routeConfig === curr.routeConfig;
}

// Asks if a snapshot for the current route already has been stored.
// Return true, if handles map contains the right snapshot and the router should re-attach this snapshot to the routing.
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
    if (this.shouldResetReuseStrategy(route)) {
        this.deactivateAllHandles();
        return false;
    }

    if (this.shouldIgnoreReuseStrategy(route)) {
        return false;
    }

    return this.handles.has(this.getKey(route));
}

// Load the snapshot from storage. It's only called, if the shouldAttach-method returned true.
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
    return this.handles.get(this.getKey(route)) || null;
}

// Asks if the snapshot should be detached from the router.
// That means that the router will no longer handle this snapshot after it has been stored by calling the store-method.
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return !this.shouldIgnoreReuseStrategy(route);
}

// After the router has asked by using the shouldDetach-method and it returned true, the store-method is called (not immediately but some time later).
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle | null): void {
    if (!handle) {
        return;
    }

    this.handles.set(this.getKey(route), handle);
}

private shouldResetReuseStrategy(route: ActivatedRouteSnapshot): boolean {
    let snapshot: ActivatedRouteSnapshot = route;

    while (snapshot.children && snapshot.children.length) {
        snapshot = snapshot.children[0];
    }

    return snapshot.data && snapshot.data.resetReuseStrategy;
}

private shouldIgnoreReuseStrategy(route: ActivatedRouteSnapshot): boolean {
    return route.data && route.data.defaultReuseStrategy;
}

private deactivateAllHandles(): void {
    this.handles.forEach((handle: DetachedRouteHandle) => this.destroyComponent(handle));
    this.handles.clear();
}

private destroyComponent(handle: DetachedRouteHandle): void {
    const componentRef: ComponentRef<any> = handle['componentRef'];

    if (componentRef) {
        componentRef.destroy();
    }
}

private getKey(route: ActivatedRouteSnapshot): string {
    return route.pathFromRoot
        .map((snapshot: ActivatedRouteSnapshot) => snapshot.routeConfig ? snapshot.routeConfig.path : '')
        .filter((path: string) => path.length > 0)
        .join('');
    }
}

3

নীচের কাজ হয়! তথ্যসূত্র: https://www.cnblogs.com/lovesangel/p/7853364.html

import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';

export class CustomReuseStrategy implements RouteReuseStrategy {

    public static handlers: { [key: string]: DetachedRouteHandle } = {}

    private static waitDelete: string

    public static deleteRouteSnapshot(name: string): void {
        if (CustomReuseStrategy.handlers[name]) {
            delete CustomReuseStrategy.handlers[name];
        } else {
            CustomReuseStrategy.waitDelete = name;
        }
    }
   
    public shouldDetach(route: ActivatedRouteSnapshot): boolean {
        return true;
    }

   
    public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
        if (CustomReuseStrategy.waitDelete && CustomReuseStrategy.waitDelete == this.getRouteUrl(route)) {
            // 如果待删除是当前路由则不存储快照
            CustomReuseStrategy.waitDelete = null
            return;
        }
        CustomReuseStrategy.handlers[this.getRouteUrl(route)] = handle
    }

    
    public shouldAttach(route: ActivatedRouteSnapshot): boolean {
        return !!CustomReuseStrategy.handlers[this.getRouteUrl(route)]
    }

    /** 从缓存中获取快照,若无则返回nul */
    public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
        if (!route.routeConfig) {
            return null
        }

        return CustomReuseStrategy.handlers[this.getRouteUrl(route)]
    }

   
    public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
        return future.routeConfig === curr.routeConfig &&
            JSON.stringify(future.params) === JSON.stringify(curr.params);
    }

    private getRouteUrl(route: ActivatedRouteSnapshot) {
        return route['_routerState'].url.replace(/\//g, '_')
    }
}


1
সাবধান, এটি একটি অভ্যন্তরীণ ভেরিয়েবল ব্যবহার করে _routerState
ডার্কনিউরন

@ ডার্কইউরন কি _routerStateক্ষতিকারক হতে পারে?
11 কে 2

2
না, তবে গুগলের কোনও পরিবর্তন নেই যে এটি অভ্যন্তরীণভাবে ব্যবহৃত হয়েছে এবং এটি API তে প্রকাশিত হয়নি around
ডার্কনিউরন

আমরা যখন ফোন করছি deleteRouteSnapshot?
k11k2

0

আমি একটি কাস্টম রুট পুনরায় ব্যবহার কৌশল প্রয়োগ করে এই সমস্যার মুখোমুখি হয়েছি:

  1. কোনও রুটে সংযুক্ত / বিচ্ছিন্নকরণের কাজ করুন: সাবস্ক্রিপশন, ক্লিনআপ ইত্যাদি পরিচালনা করুন;
  2. শুধুমাত্র শেষ প্যারামিটারাইজড রুটের রাজ্য সংরক্ষণ করুন: মেমরি অপ্টিমাইজেশন;
  3. একটি উপাদান নয়, একটি রাজ্য পুনরায় ব্যবহার করুন: রাজ্যকে ম্যানেজমেন্ট সরঞ্জাম দিয়ে রাজ্য পরিচালনা করুন।
  4. "ভিন্ন রুট থেকে তৈরি করা সক্রিয় রৌটস্নাপশট পুনরায় সংযুক্ত করা যায় না" ত্রুটি;

তাই আমি এই সমস্যাগুলি সমাধান করে একটি লাইব্রেরি লিখেছি। লাইব্রেরিটি সংযুক্ত / বিচ্ছিন্ন হুকের জন্য একটি পরিষেবা এবং সজ্জকার সরবরাহ করে এবং কোনও রুটের পথ নয়, বিচ্ছিন্ন রুটগুলি সংরক্ষণ করার জন্য রুটের উপাদানগুলি ব্যবহার করে।

উদাহরণ:

/* Usage with decorators */
@onAttach()
public onAttach(): void {
  // your code...
}

@onDetach()
public onDetach(): void {
  // your code...
}

/* Usage with a service */
public ngOnInit(): void {
  this.cacheRouteReuse
    .onAttach(HomeComponent) // or any route's component
    .subscribe(component => {
      // your code...
    });

  this.cacheRouteReuse
    .onDetach(HomeComponent) // or any route's component
    .subscribe(component => {
      // your code...
    });
}

গ্রন্থাগার: https://www.npmjs.com/package/ng-cache-route-reuse


কেবল নিজের লাইব্রেরি বা টিউটোরিয়ালের সাথে লিঙ্ক করা ভাল উত্তর নয়। এটির সাথে লিঙ্ক করা, কেন এটি সমস্যার সমাধান করে তা ব্যাখ্যা করে, কীভাবে এটি করা যায় তার কোড সরবরাহ করা এবং আপনি যে এটি লিখেছিলেন তা অস্বীকার করা আরও উত্তরের জবাব দেয়। দেখুন: "ভাল" স্ব প্রচারের কী বোঝায়?
পল রাউব
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.