অ্যাপ.সেটিংস - কৌণিক উপায়?


90

আমি App Settingsআমার অ্যাপে এমন একটি বিভাগ যুক্ত করতে চাই যেখানে এতে কিছু কনসেট এবং পূর্বনির্ধারিত মান থাকবে।

আমি ইতিমধ্যে এই উত্তরটি ব্যবহার করেছি যা ব্যবহার করে OpaqueTokenতবে এটি কৌণিকর মধ্যে অবচিত হয়। এই নিবন্ধটি পার্থক্যগুলি ব্যাখ্যা করে তবে এটি একটি পূর্ণ উদাহরণ দেয় নি, এবং আমার প্রচেষ্টা ব্যর্থ হয়েছিল।

এখানে আমি যা চেষ্টা করেছি তা এখানে (সঠিক উপায় কিনা তা আমি জানি না):

//ServiceAppSettings.ts

import {InjectionToken, OpaqueToken} from "@angular/core";

const CONFIG = {
  apiUrl: 'http://my.api.com',
  theme: 'suicid-squad',
  title: 'My awesome app'
};
const FEATURE_ENABLED = true;
const API_URL = new InjectionToken<string>('apiUrl');

এবং এটি সেই উপাদানটি যেখানে আমি সেই কনসগুলি ব্যবহার করতে চাই:

//MainPage.ts

import {...} from '@angular/core'
import {ServiceTest} from "./ServiceTest"

@Component({
  selector: 'my-app',
  template: `
   <span>Hi</span>
  ` ,  providers: [
    {
      provide: ServiceTest,
      useFactory: ( apiUrl) => {
        // create data service
      },
      deps: [

        new Inject(API_URL)
      ]
    }
  ]
})
export class MainPage {


}

তবে এটি কাজ করে না এবং আমি ত্রুটিগুলি পাই।

প্রশ্ন:

আমি কীভাবে "অ্যাপ.সেটেটিংগুলি" কৌণিক উপায়ে মূল্যায়ন করতে পারি?

চূর্ণকারী

এনবি শিওর আমি ইনজেকটেবল পরিষেবা তৈরি করতে এবং এটি এনজিডমডুলের সরবরাহকারীর মধ্যে রাখতে পারি, তবে আমি যেমন বলেছিলাম যে আমি এটি কৌনিক উপায়ের সাথে করতে চাই InjectionToken


আপনি এখানে বর্তমান সরকারী দস্তাবেজগুলির ভিত্তিতে আমার উত্তরটি চেক করতে পারেন
জাভিয়রফুয়েন্টেস

@ জাভিয়ের নং আপনার লিঙ্কটিতে একটি সমস্যা রয়েছে যদি দুটি সরবরাহকারী একই নাম সরবরাহ করে তবে আপনার এখন সমস্যা হয়। ওপাওকোটোকেন প্রবেশ করছেন
রই নমির

আপনি জানেন [ওপাক টোকেন অবচিত হ'ল] ( কৌণিক.ইও / এপি / কোর / ওপাক টোকেন ) এই নিবন্ধটি কীভাবে কৌণিক সরবরাহকারীগুলিতে নাম সংঘর্ষ রোধ করতে হবে সে সম্পর্কে আলোচনা করেছে
জাভিয়েরফুয়েন্টস

ইয়েহে আমি জানি কিন্তু এখনও লিঙ্কযুক্ত নিবন্ধটি ভুল।
রই নমির

4
নীচের লিঙ্কটি প্রত্যেকের জন্য সহায়ক হতে পারে যারা কৌণিক কনফিগার স্কিমার নতুন আর্কিটেকচার ব্যবহার করতে পছন্দ করে ডেভলবস.মাইক্রোসফট
প্রিমিয়ার-

উত্তর:


58

ইনজেকশন টোকেন্স (নীচের উদাহরণ দেখুন) দিয়ে এটি কীভাবে করবেন তা আমি বুঝতে পেরেছি এবং যদি আপনার প্রকল্পটি ব্যবহার করে তৈরি করা হয় তবে Angular CLIআপনি এপিআই এন্ডপয়েন্টের মতো /environmentsস্থির জন্য পাওয়া পরিবেশের ফাইলগুলি ব্যবহার করতে পারেন application wide settingsতবে আপনার প্রকল্পের প্রয়োজনীয়তার উপর নির্ভর করে আপনি সম্ভবত শেষ পর্যন্ত যাবেন উভয়টি ব্যবহার করে যেহেতু এনভায়রনমেন্ট ফাইলগুলি কেবলমাত্র আক্ষরিক বস্তু, তবে ইনজেক্টেবল কনফিগারেশন InjectionTokenপরিবেশের ভেরিয়েবলগুলি ব্যবহার করতে পারে এবং যেহেতু এটির কোনও শ্রেণি অ্যাপ্লিকেশনের অন্যান্য কারণগুলির উপর ভিত্তি করে এটি কনফিগার করার জন্য যুক্তি প্রয়োগ করতে পারে যেমন প্রাথমিক http অনুরোধ ডেটা, সাবডোমেন ইত্যাদি

ইনজেকশন টোকেন উদাহরণ

/app/app-config.module.ts

import { NgModule, InjectionToken } from '@angular/core';
import { environment } from '../environments/environment';

export let APP_CONFIG = new InjectionToken<AppConfig>('app.config');

export class AppConfig {
  apiEndpoint: string;
}

export const APP_DI_CONFIG: AppConfig = {
  apiEndpoint: environment.apiEndpoint
};

@NgModule({
  providers: [{
    provide: APP_CONFIG,
    useValue: APP_DI_CONFIG
  }]
})
export class AppConfigModule { }

/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppConfigModule } from './app-config.module';

@NgModule({
  declarations: [
    // ...
  ],
  imports: [
    // ...
    AppConfigModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

এখন আপনি এটিকে কোনও উপাদান, পরিষেবা ইত্যাদিতে ডিআই করতে পারেন:

/app/core/auth.service.ts

import { Injectable, Inject } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

import { APP_CONFIG, AppConfig } from '../app-config.module';
import { AuthHttp } from 'angular2-jwt';

@Injectable()
export class AuthService {

  constructor(
    private http: Http,
    private router: Router,
    private authHttp: AuthHttp,
    @Inject(APP_CONFIG) private config: AppConfig
  ) { }

  /**
   * Logs a user into the application.
   * @param payload
   */
  public login(payload: { username: string, password: string }) {
    return this.http
      .post(`${this.config.apiEndpoint}/login`, payload)
      .map((response: Response) => {
        const token = response.json().token;
        sessionStorage.setItem('token', token); // TODO: can this be done else where? interceptor
        return this.handleResponse(response); // TODO:  unset token shouldn't return the token to login
      })
      .catch(this.handleError);
  }

  // ...
}

এরপরে আপনি রফতানি হওয়া অ্যাপকনফিগ ব্যবহার করে কনফিগারেশন পরীক্ষা করে টাইপ করতে পারেন।


না, তবে আপনি আক্ষরিক অর্থে প্রথম অংশটি কোনও ফাইলে অনুলিপি করে আটকে দিতে পারেন, এটি আপনার অ্যাপ্লিকেশন mod আমি এটি একটি প্লাঙ্কারে সেট আপ করতে আরও বেশি সময় নেব তবে এই পদক্ষেপগুলি করতে হবে।
এমটিপল্টজ

ওহ আমি ভেবেছিলাম আপনার ইতিমধ্যে এর জন্য একটি নিমজ্জনকারী রয়েছে :-) আপনাকে ধন্যবাদ।
রই নমির

যারা চান তাদের জন্য: plnkr.co/edit/2YMZk5mhP1B4jTgA37B8?p= পূর্বরূপ
রই নমির

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

4
আমি অ্যাজির এনভায়রনমেন্ট ভেরিয়েবল এবং জেএসএন ট্রান্সফর্ম বৈশিষ্ট্যগুলি ব্যবহার করে এপিআই এন্ডপয়েন্টটি ইনজেক্ট করার চেষ্টা করছি, তবে দেখে মনে হচ্ছে এই উত্তরটি কেবলমাত্র এনভায়রনমেন্ট ফাইল থেকে এপিআইপয়েন্ট পেয়েছে। আপনি কীভাবে এটিকে কনফিগার থেকে ধরে এক্সপোর্ট করবেন?
আর্চিবাল্ড

138

আপনি যদি ব্যবহার করছেন , আরও একটি বিকল্প আছে:

কৌণিক সিএলআই src/environments(ডিফল্ট ফাইলগুলি environment.ts(ডিভ) এবং environment.prod.ts(উত্পাদন)) এ পরিবেশ ফাইল সরবরাহ করে ।

মনে রাখবেন যে আপনাকে সমস্ত environment.*ফাইলগুলিতে কনফিগার পরামিতি সরবরাহ করতে হবে , যেমন,

পরিবেশ.টস :

export const environment = {
  production: false,
  apiEndpoint: 'http://localhost:8000/api/v1'
};

পরিবেশ.প্রড.টস :

export const environment = {
  production: true,
  apiEndpoint: '__your_production_server__'
};

এবং সেগুলি আপনার সেবায় ব্যবহার করুন (সঠিক পরিবেশ ফাইলটি স্বয়ংক্রিয়ভাবে নির্বাচিত হয়):

api.service.ts

// ... other imports
import { environment } from '../../environments/environment';

@Injectable()
export class ApiService {     

  public apiRequest(): Observable<MyObject[]> {
    const path = environment.apiEndpoint + `/objects`;
    // ...
  }

// ...
}

গিথুব (কৌণিক সিএলআই সংস্করণ 6) বা অফিসিয়াল কৌণিক নির্দেশিকায় (সংস্করণ 7) অ্যাপ্লিকেশন পরিবেশ সম্পর্কে আরও পড়ুন ।


4
তার fine.But কাজ করার সময় বিল্ড চলন্ত এটি bundle.I মধ্যে configuartion পরিবর্তন করা উচিত হিসাবে পরিবর্তিত হয় আমার পরিবেশন করা কোডে করতে প্রযোজনার চলন্ত পর
kamalav

44
এটি সাধারণ সফ্টওয়্যার বিকাশে কিছুটা অ্যান্টি-প্যাটার্ন; এপিআই url কেবল কনফিগারেশন। ভিন্ন পরিবেশের জন্য অ্যাপটিকে পুনরায় কনফিগার করতে এটি পুনর্নির্মাণ গ্রহণ করা উচিত নয়। এটি একবারে তৈরি করা উচিত, বহুবার মোতায়েন করা উচিত (প্রাক-প্রোড, স্টেজিং, প্রোড ইত্যাদি)।
ম্যাট টেস্টার

4
@ ম্যাটটেষ্টার এটিই এখন অফিশিয়াল অ্যাঙ্গুলার-সিএলআইয়ের গল্প। যদি আপনার এই প্রশ্নের আরও ভাল উত্তর হয়: এটি নির্দ্বিধায় পোস্ট করুন!
tilo

7
এটি এনজি বিল্ডের পরে কনফিগারযোগ্য?
এনকে

4
ওহ ওকে, আমি মন্তব্যগুলি ভুল লিখেছি। আমি একমত হয়েছি যে এটি একটি অ্যান্টি-প্যাটার্নকে ndsণ দেয়, আমি ভেবেছিলাম গতিশীল রান টাইম কনফিগারেশনের জন্য একটি গল্প আছে।
জেনস বোডাল

89

environment.*.tsআপনার এপিআই URL টি কনফিগারেশনের জন্য ফাইলগুলি ব্যবহার করা ভাল নয় advis দেখে মনে হচ্ছে আপনার উচিত কারণ এটি "পরিবেশ" শব্দের উল্লেখ করে।

এটি ব্যবহার করা আসলে সংকলন-সময় কনফিগারেশন । আপনি যদি API টি ইউআরএল পরিবর্তন করতে চান তবে আপনাকে পুনর্নির্মাণ করতে হবে। এটি এমন কিছু যা আপনি করতে চান না ... কেবল আপনার বন্ধুত্বপূর্ণ QA বিভাগটি জিজ্ঞাসা করুন :)

আপনার যা দরকার তা হ'ল রানটাইম কনফিগারেশন , অর্থাত অ্যাপটি শুরু হওয়ার সাথে সাথে এটির কনফিগারেশন লোড করে।

আরও কিছু উত্তর এতে স্পর্শ করে, তবে পার্থক্যটি হ'ল অ্যাপটি শুরু হওয়ার সাথে সাথে কনফিগারেশনটি লোড করা দরকার , যাতে এটি যখনই প্রয়োজন তখনই এটি কোনও সাধারণ পরিষেবা ব্যবহার করতে পারে।

রানটাইম কনফিগারেশন প্রয়োগ করতে:

  1. /src/assets/ফোল্ডারে একটি JSON কনফিগারেশন ফাইল যুক্ত করুন (যাতে এটি বিল্ডে অনুলিপি করা হয়)
  2. AppConfigServiceকনফিগার লোড এবং বিতরণ করতে একটি তৈরি করুন
  3. একটি ব্যবহার করে কনফিগারেশন লোড করুন APP_INITIALIZER

1. কনফিগারেশন ফাইল যুক্ত করুন /src/assets

আপনি এটিকে অন্য ফোল্ডারে যুক্ত করতে পারেন, তবে আপনাকে সিএলআইকে জানাতে হবে যে এটি একটি সম্পদ angular.json। সম্পদ ফোল্ডারটি ব্যবহার শুরু করুন:

{
  "apiBaseUrl": "https://development.local/apiUrl"
}

2. তৈরি করুন AppConfigService

এটি সার্ভিস যা ইনজেকশন করা হবে যখনই আপনার কনফিগার মানটির প্রয়োজন হবে:

@Injectable({
  providedIn: 'root'
})
export class AppConfigService {

  private appConfig: any;

  constructor(private http: HttpClient) { }

  loadAppConfig() {
    return this.http.get('/assets/config.json')
      .toPromise()
      .then(data => {
        this.appConfig = data;
      });
  }

  // This is an example property ... you can make it however you want.
  get apiBaseUrl() {

    if (!this.appConfig) {
      throw Error('Config file not loaded!');
    }

    return this.appConfig.apiBaseUrl;
  }
}

3. একটি ব্যবহার করে কনফিগারেশন লোড করুন APP_INITIALIZER

AppConfigServiceসম্পূর্ণরূপে কনফিগার করা লোড সহ নিরাপদে ইনজেকশনের অনুমতি দেওয়ার জন্য আমাদের অ্যাপ্লিকেশন শুরুর সময় কনফিগারটি লোড করতে হবে। গুরুত্বপূর্ণভাবে, সূচনা কারখানার ফাংশনটির Promiseএমন একটি ফিরে আসা দরকার যাতে কৌণিক সূচনা শেষ হওয়ার আগে সমাধান শেষ না হওয়া পর্যন্ত অপেক্ষা করতে জানে:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [
    {
      provide: APP_INITIALIZER,
      multi: true,
      deps: [AppConfigService],
      useFactory: (appConfigService: AppConfigService) => {
        return () => {
          //Make sure to return a promise!
          return appConfigService.loadAppConfig();
        };
      }
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

আপনার প্রয়োজন যেখানেই এটি এখন ইনজেক্ট করতে পারেন এবং সমস্ত কনফিগারেশন পড়ার জন্য প্রস্তুত থাকবে:

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {

  apiBaseUrl: string;

  constructor(private appConfigService: AppConfigService) {}

  ngOnInit(): void {
    this.apiBaseUrl = this.appConfigService.apiBaseUrl;
  }

}

আমি এটি দৃ strongly়ভাবে বলতে পারি না, আপনার API url কে সংকলন-সময় কনফিগারেশন হিসাবে কনফিগার করা একটি অ্যান্টি-প্যাটার্ন । রানটাইম কনফিগারেশন ব্যবহার করুন।


4
স্থানীয় ফাইল বা বিভিন্ন পরিষেবা, সংকলন-সময় কনফিগারটি কোনও API url এর জন্য ব্যবহার করা উচিত নয়। আপনার অ্যাপটি কোনও পণ্য (ইনস্টল করার জন্য ক্রেতা) হিসাবে বিক্রি হয়ে থাকে, আপনি সেগুলি এটি সংকলন করতে চান না ইত্যাদি ither যে কোনও উপায়ে আপনি 2 বছর আগে নির্মিত কিছু পুনরায় সংকলন করতে চান না, কেবল কারণ API url পরিবর্তন হয়েছে। ঝুকি!!
ম্যাট টেস্টার

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

4
@ ম্যাটটেষ্টার - যদি কৌনিক কখনও এই বৈশিষ্ট্যটি প্রয়োগ করে তবে এটি আমাদের সমস্যার সমাধান করবে: github.com/angular/angular/issues/23279#issuecomment-528417026
মাইক Becatti

4
@ ক্রিশ্চিয়ান রামিরেজ এটি অ্যাপের দৃষ্টিকোণ থেকে: রানটাইম হওয়া পর্যন্ত কনফিগারেশনটি জানা যায় না এবং স্থির ফাইলটি বিল্ডের বাইরে থাকে এবং স্থাপনার সময়ে বিভিন্ন উপায়ে সেট করা যায়। স্ট্যাটিক ফাইল অ সংবেদনশীল কনফিগারেশনের জন্য সূক্ষ্ম। একটি কৌশল বা অন্য কোনও সুরক্ষিত এন্ড-পয়েন্ট একই কৌশলটি দিয়ে সম্ভব, তবে কীভাবে এটিকে সুরক্ষিত করার জন্য অনুমোদন করবেন তা আপনার পরবর্তী চ্যালেঞ্জ।
ম্যাট টেস্টার

4
@ ডালেক লাইনের মধ্যে পড়া, আপনি ওয়েব ডিপ্লাই ব্যবহার করে নিযুক্ত করছেন। আপনি যদি অ্যাজুর ডিভোপ্সের মতো কোনও ডিপোরিয়মেন্ট পাইপলাইন ব্যবহার করেন তবে কনফিগার ফাইলটি পরবর্তী পদক্ষেপ হিসাবে সঠিকভাবে সেট করা সম্ভব। কনফিগারটির সেটিংস স্থাপনের প্রক্রিয়া / পাইপলাইনের দায়িত্ব, যা ডিফল্ট কনফিগার ফাইলে মানগুলিকে ওভাররাইড করতে পারে। আশা করি তা স্পষ্ট হয়ে গেছে।
ম্যাট পরীক্ষক

8

আমার সমাধানটি এখানে, পুনর্নির্মাণ না করে পরিবর্তনের অনুমতি দেওয়ার জন্য .json থেকে লোড

import { Injectable, Inject } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Location } from '@angular/common';

@Injectable()
export class ConfigService {

    private config: any;

    constructor(private location: Location, private http: Http) {
    }

    async apiUrl(): Promise<string> {
        let conf = await this.getConfig();
        return Promise.resolve(conf.apiUrl);
    }

    private async getConfig(): Promise<any> {
        if (!this.config) {
            this.config = (await this.http.get(this.location.prepareExternalUrl('/assets/config.json')).toPromise()).json();
        }
        return Promise.resolve(this.config);
    }
}

এবং config.json

{
    "apiUrl": "http://localhost:3000/api"
}

4
এই পদ্ধতির সাথে সমস্যা হ'ল কনফিগারেশন.জসন বিশ্বের জন্য উন্মুক্ত। আপনি www.mywebsite.com/assetts/config.json টাইপ করতে কাউকে কীভাবে আটকাবেন?
আলবার্তো এল বনফিগলিও

4
@ অ্যালবার্তোল.বোনফিগলিও আপনি সার্ভারটি কনফিগার করেছেন বাইরে থেকে কনফিগার.জেডন ফাইলের অ্যাক্সেসের অনুমতি না দেওয়ার জন্য (বা এটি কোনও ডিরেক্টরিতে রাখুন যাতে জনসাধারণের অ্যাক্সেস নেই)
অ্যালেক্স পান্ড্রিয়ার

এটি আমার প্রিয় সমাধানও, তবে সুরক্ষা ঝুঁকি নিয়ে এখনও উদ্বিগ্ন।
ভিকমন্টানা

7
দয়া করে, আপনি কি আমাকে এটি সঠিকভাবে পেতে সহায়তা করতে পারেন? কৌণিক পরিবেশের জন্য এটি কীভাবে প্রথাগতের চেয়ে ঝুঁকিপূর্ণ? সম্পূর্ণ সামগ্রী environments.prod.tsপর ng build --prodকিছু হতে হবে .jsকিছু সময়ে ফাইল। এমনকি যদি অবরুদ্ধ হয়ে থাকে তবে এ থেকে প্রাপ্ত ডেটা environments.prod.tsপরিষ্কার লেখায় থাকবে। এবং সমস্ত .js ফাইল হিসাবে এটি শেষ ব্যবহারকারী মেশিনে উপলব্ধ।
ইগান

4
@ আলবার্তো.বোনফিগলিও যেহেতু একটি কৌণিক অ্যাপ্লিকেশন প্রকৃতির দ্বারা ক্লায়েন্ট অ্যাপ্লিকেশন, এবং জাভাস্ক্রিপ্ট ডেটা এবং কনফিগারেশনের চারপাশে যাওয়ার জন্য ব্যবহৃত হবে, এতে কোনও গোপন কনফিগারেশন ব্যবহার করা উচিত নয়; সমস্ত গোপন কনফিগারেশন সংজ্ঞাগুলি এমন কোনও এপিআই স্তরের পিছনে থাকা উচিত যেখানে ব্যবহারকারীর ব্রাউজার বা ব্রাউজার সরঞ্জামগুলি এটি অ্যাক্সেস করতে পারে না। একটি এপিআই এর বেস ইউআরআইয়ের মতো মানগুলি জনসাধারণের অ্যাক্সেসের জন্য ঠিক আছে কারণ ব্যবহারকারীর লগ ইন (https এর উপরে বহনকারী টোকেন) এর উপর ভিত্তি করে API এর নিজস্ব শংসাপত্র এবং সুরক্ষা থাকা উচিত।
টমি এলিয়ট

5

দরিদ্র মানুষের কনফিগারেশন ফাইল:

বডি ট্যাগে প্রথম লেন হিসাবে আপনার সূচকটি। Html এ যুক্ত করুন:

<script lang="javascript" src="assets/config.js"></script>

সম্পদ / config.js যুক্ত করুন:

var config = {
    apiBaseUrl: "http://localhost:8080"
}

কনফিগারেশন যুক্ত করুন:

export const config: AppConfig = window['config']

export interface AppConfig {
    apiBaseUrl: string
}

গুরুত্ব সহকারে, এটির সমাধানগুলির মধ্যে বেশিরভাগ মৌলিক উপাদানগুলির মধ্যে সিদ্ধ করার জন্য এবং এখনও ধরণের ধারাবাহিকতা বজায় রাখার জন্য +1।
আলোকিত

5

আমি দেখতে পেয়েছি যে এর APP_INITIALIZERজন্য একটি ব্যবহার করা এমন পরিস্থিতিতে কাজ করে না যেখানে অন্যান্য পরিষেবা সরবরাহকারীদের কনফিগারেশনটি ইঞ্জেকশনের প্রয়োজন require APP_INITIALIZERচালানোর আগে এগুলি তাত্ক্ষণিকভাবে ব্যবহার করা যেতে পারে ।

আমি অন্য সমাধানগুলি দেখেছি যা fetchএকটি কনফিগারেশন.জসন ফাইল পড়তে ব্যবহার করে platformBrowserDynamic()এবং মূল মডিউলটি বুটস্ট্র্যাপ করার আগে প্যারামিটারে ইঞ্জেকশন টোকেন ব্যবহার করে এটি সরবরাহ করে । তবে fetchআমি টার্গেট করা মোবাইল ডিভাইসের জন্য সমস্ত ব্রাউজার এবং নির্দিষ্ট ওয়েবভিউ ব্রাউজারগুলিতে সমর্থিত নয়।

নিম্নলিখিতটি এমন একটি সমাধান যা আমার জন্য পিডাব্লুএ এবং মোবাইল ডিভাইস (ওয়েবভিউ) উভয়ের জন্য কাজ করে। দ্রষ্টব্য: আমি এখন পর্যন্ত কেবলমাত্র অ্যান্ড্রয়েডে পরীক্ষা করেছি; বাড়ি থেকে কাজ করার অর্থ আমার কাছে কোনও ম্যাক তৈরির অ্যাক্সেস নেই।

ইন main.ts:

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { APP_CONFIG } from './app/lib/angular/injection-tokens';

function configListener() {
  try {
    const configuration = JSON.parse(this.responseText);

    // pass config to bootstrap process using an injection token
    platformBrowserDynamic([
      { provide: APP_CONFIG, useValue: configuration }
    ])
      .bootstrapModule(AppModule)
      .catch(err => console.error(err));

  } catch (error) {
    console.error(error);
  }
}

function configFailed(evt) {
  console.error('Error: retrieving config.json');
}

if (environment.production) {
  enableProdMode();
}

const request = new XMLHttpRequest();
request.addEventListener('load', configListener);
request.addEventListener('error', configFailed);
request.open('GET', './assets/config/config.json');
request.send();

এই কোড:

  1. config.jsonফাইলটির জন্য একটি অ্যাসিঙ্ক অনুরোধ বন্ধ করে দেয় ।
  2. যখন অনুরোধটি সম্পূর্ণ হয়, JSON কে জাভাস্ক্রিপ্ট অবজেক্টে পার্স করে
  3. APP_CONFIGবুটস্ট্র্যাপিংয়ের আগে ইনজেকশন টোকেন ব্যবহার করে মান সরবরাহ করে ।
  4. এবং শেষ পর্যন্ত রুট মডিউলটি বুটস্ট্র্যাপ করে।

APP_CONFIGএরপরে কোনও অতিরিক্ত সরবরাহকারীতে ইনজেকশন দেওয়া যেতে পারে app-module.tsএবং এটি সংজ্ঞায়িত করা হবে। উদাহরণস্বরূপ, আমি নিম্নলিখিতটি দিয়ে FIREBASE_OPTIONSইনজেকশন টোকেনটি শুরু করতে পারি @angular/fire:

{
      provide: FIREBASE_OPTIONS,
      useFactory: (config: IConfig) => config.firebaseConfig,
      deps: [APP_CONFIG]
}

খুব সাধারণ প্রয়োজনের জন্য আমি এই পুরো জিনিসটি আশ্চর্যজনকভাবে কঠিন (এবং হ্যাকি) জিনিস করতে পেলাম। আশা করি অদূর ভবিষ্যতে আরও একটি ভাল উপায় হবে যেমন অ্যাসিঙ্ক সরবরাহকারী কারখানার জন্য সহায়তা support

সম্পূর্ণতার জন্য বাকী কোডটি ...

ইন app/lib/angular/injection-tokens.ts:

import { InjectionToken } from '@angular/core';
import { IConfig } from '../config/config';

export const APP_CONFIG = new InjectionToken<IConfig>('app-config');

এবং app/lib/config/config.tsআমি আমার JSON কনফিগারেশন ফাইলের জন্য ইন্টারফেসটি সংজ্ঞায়িত করেছি:

export interface IConfig {
    name: string;
    version: string;
    instance: string;
    firebaseConfig: {
        apiKey: string;
        // etc
    }
}

কনফিগার এতে সংরক্ষণ করা হয় assets/config/config.json:

{
  "name": "my-app",
  "version": "#{Build.BuildNumber}#",
  "instance": "localdev",
  "firebaseConfig": {
    "apiKey": "abcd"
    ...
  }
}

দ্রষ্টব্য: আমি বিল্ড.বাইল্ডবার্বার সন্নিবেশ করানোর জন্য একটি অ্যাজুরি ডিভোপস টাস্ক ব্যবহার করি এবং এটি মোতায়েনের সাথে সাথে বিভিন্ন স্থাপনার পরিবেশের জন্য অন্যান্য সেটিংসের বিকল্প রাখি।


2

এটির জন্য আমার দুটি সমাধান এখানে

1. জসন ফাইলগুলিতে স্টোর করুন

কেবল একটি জসন ফাইল তৈরি করুন এবং $http.get()পদ্ধতিতে আপনার উপাদানটিতে প্রবেশ করুন । আমার যদি এটি খুব কম প্রয়োজন হয় তবে এটি ভাল এবং দ্রুত।

২. ডেটা পরিষেবা ব্যবহার করে সঞ্চয় করুন

আপনি যদি সমস্ত উপাদানগুলিতে সঞ্চয় করতে এবং ব্যবহার করতে চান বা বড় ব্যবহার করতে চান তবে ডেটা পরিষেবাটি ব্যবহার করা আরও ভাল। এটার মত :

  1. ফোল্ডারের ভিতরে কেবল স্থির ফোল্ডার তৈরি করুন src/app

  2. fuels.tsস্ট্যাটিক ফোল্ডার হিসাবে নামক একটি ফাইল তৈরি করুন । আপনি এখানে অন্যান্য স্থিতিশীল ফাইলও সংরক্ষণ করতে পারেন। আপনার ডেটাটি এর মতো সংজ্ঞায়িত করা যাক। ধরে নিচ্ছি আপনার জ্বালানির ডেটা রয়েছে।

__

export const Fuels {

   Fuel: [
    { "id": 1, "type": "A" },
    { "id": 2, "type": "B" },
    { "id": 3, "type": "C" },
    { "id": 4, "type": "D" },
   ];
   }
  1. একটি ফাইলের নাম স্ট্যাটিক.সার্ভিস.সেট তৈরি করুন

__

import { Injectable } from "@angular/core";
import { Fuels } from "./static/fuels";

@Injectable()
export class StaticService {

  constructor() { }

  getFuelData(): Fuels[] {
    return Fuels;
  }
 }`
  1. এখন আপনি প্রতিটি মডিউল জন্য এটি উপলব্ধ করতে পারেন

কেবল এই জাতীয় অ্যাপ্লিকেশন.মডিউল.এসটি ফাইল আমদানি করুন এবং সরবরাহকারীর পরিবর্তন করুন

import { StaticService } from './static.services';

providers: [StaticService]

এখন StaticServiceএটি কোনও মডিউল হিসাবে ব্যবহার করুন ।

এখানেই শেষ.


ভাল সমাধান যেহেতু আপনাকে পুনরায় সংশোধন করতে হবে না। পরিবেশ কোডটিতে এটি হার্ড-কোডিংয়ের মতো। নোংরা। +1
টেরেন্স 100

0

আমি এই কৌণিকটি কীভাবে খুঁজে পাই : মাইক্রোসফ্ট ডেভ ব্লগের সম্পাদনাযোগ্য কনফিগার ফাইলগুলি সর্বোত্তম সমাধান হতে পারে। আপনি ডেভ বিল্ড সেটিংস বা প্রোড বিল্ড সেটিংস কনফিগার করতে পারেন।


0

আমি যোগদানের আগে এবং ব্যবহারকারী এবং পরিবেশের তথ্যের জন্য স্থানীয় স্টোরেজ ব্যবহার করে এমন একটি সমাধান করার আগে কয়েক বছর আগে আমাদের এই সমস্যা হয়েছিল। কৌণিক 1.0 দিন সঠিক। আমরা আগে গতিশীলভাবে রানটাইমে একটি জেএস ফাইল তৈরি করেছিলাম যা তখন তৈরি হওয়া এপিআই ইউআরএলকে একটি বৈশ্বিক চলক হিসাবে স্থাপন করবে। আমরা এই দিনগুলিতে আরও কিছু OOP চালিত এবং কোনও কিছুর জন্য স্থানীয় সঞ্চয়স্থান ব্যবহার করি না।

পরিবেশ এবং এপিআই ইউআরএল নির্মাণ উভয়ের জন্য আমি আরও ভাল সমাধান তৈরি করেছি।

এটি কীভাবে আলাদা?

কনফিগারেশন.জসন ফাইল লোড না হওয়া পর্যন্ত অ্যাপটি লোড হবে না। এটি এসওসি-র একটি উচ্চতর ডিগ্রি তৈরি করতে কারখানার ফাংশন ব্যবহার করে। আমি এটিকে কোনও পরিষেবাতে আবদ্ধ করতে পারি, তবে আমি কখনই কোনও কারণ দেখিনি যখন ফাইলটির বিভিন্ন বিভাগের মধ্যে একমাত্র মিলটি হ'ল তারা ফাইলটিতে একত্রে উপস্থিত থাকে। কারখানার ক্রিয়াকলাপটি আমাকে ফাংশনটি গ্রহণ করতে সক্ষম হলে সরাসরি মডিউলটিতে ফাংশনটি পাস করার অনুমতি দেয়। সবশেষে, যখন ফ্যাক্টরি ফাংশনগুলি ব্যবহারের জন্য উপলব্ধ থাকে তখন আমার ইনজেকশন টোকেন সেটআপ করার সহজ সময় হয়।

ডাউনসাইডস?

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

নির্দেশনা

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

- এখানেই আমার সমাধানটি সত্যিই আলাদা হতে শুরু করে -

  1. একটি ইন্টারফেস রফতানি করে এমন একটি ফাইল তৈরি করুন যার কাঠামোটি আপনার কনফিগারেশনকে উপস্থাপন করে - এটি সত্যিকারের ধরণের ধারাবাহিকতায় সহায়তা করে এবং কোডের পরবর্তী বিভাগের জন্য একটি প্রকারের প্রয়োজন হয়, এবং নির্দিষ্ট করে না {}বা anyযখন আপনি জানেন যে আপনি আরও কিছু নির্দিষ্ট করতে পারেন
  2. এমন আচরণ আচরণটি তৈরি করুন যা আপনি পার্সড জেসন ফাইলটি ৩ য় ধাপে পাস করবেন।
  3. এসওসি বজায় রাখতে আপনার কনফিগারেশনের বিভিন্ন বিভাগের রেফারেন্স করতে কারখানার ফাংশন ব্যবহার করুন
  4. আপনার কারখানার কার্যকারিতার ফলাফলের প্রয়োজন এমন সরবরাহকারীদের জন্য ইনজেকশনটোকেনস তৈরি করুন

- এবং / বা -

  1. কারখানার ফাংশনগুলি সরাসরি তার ফর রুট () বা ফরচিল্ড () পদ্ধতিতে কোনও ফাংশন গ্রহণ করতে সক্ষম মডিউলগুলিতে পাস করুন।

- main.ts

আমি উইন্ডো ["পরিবেশ"] চেক করে একটি ইভেন্ট শ্রোতা তৈরির আগে এমন সমাধানের সম্ভাব্যতাটিকে মঞ্জুরি দেয় না যেখানে উইন্ডো ["এনভায়রনমেন্ট"] মেইন.এস.টিতে কোড কার্যকর করার আগে অন্য কোনও উপায়ে পপুলেট করে।

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { configurationSubject } from './app/utils/environment-resolver';

var configurationLoadedEvent = document.createEvent('Event');
configurationLoadedEvent.initEvent('config-set', true, true);
fetch("../../assets/config.json")
.then(result => { return result.json(); })
.then(data => {
  window["environment"] = data;
  document.dispatchEvent(configurationLoadedEvent);
}, error => window.location.reload());

/*
  angular-cli only loads the first thing it finds it needs a dependency under /app in main.ts when under local scope. 
  Make AppModule the first dependency it needs and the rest are done for ya. Event listeners are 
  ran at a higher level of scope bypassing the behavior of not loading AppModule when the 
  configurationSubject is referenced before calling platformBrowserDynamic().bootstrapModule(AppModule)

  example: this will not work because configurationSubject is the first dependency the compiler realizes that lives under 
  app and will ONLY load that dependency, making AppModule an empty object.

  if(window["environment"])
  {
    if (window["environment"].production) {
      enableProdMode();
    }
    configurationSubject.next(window["environment"]);
    platformBrowserDynamic().bootstrapModule(AppModule)
    .catch(err => console.log(err));
  }
*/
if(!window["environment"]) {
  document.addEventListener('config-set', function(e){
    if (window["environment"].production) {
      enableProdMode();
    }
    configurationSubject.next(window["environment"]);
    window["environment"] = undefined;
    platformBrowserDynamic().bootstrapModule(AppModule)
    .catch(err => console.log(err));
  });
}

--- পরিবেশ-সমাধানকারী

অপ্রয়োজনীয়তার জন্য আমি উইন্ডো ["পরিবেশ"] ব্যবহার করে আচরণবিধিটিকে একটি মান নির্ধারণ করি। আপনি এমন একটি সমাধান প্রস্তুত করতে পারেন যেখানে আপনার কনফিগারেশনটি ইতিমধ্যে প্রিললোড হয়েছে এবং উইন্ডো ["এনভায়রনমেন্ট"] ইতিমধ্যে মুখ্য. কোডগুলির কোড সহ আপনার অ্যাংুলারের অ্যাপ্লিকেশন কোড চালুর সময় ইতিমধ্যে পপুলেটে গেছে

import { BehaviorSubject } from "rxjs";
import { IConfig } from "../config.interface";

const config = <IConfig>Object.assign({}, window["environment"]);
export const configurationSubject = new BehaviorSubject<IConfig>(config);
export function resolveEnvironment() {
  const env = configurationSubject.getValue().environment;
  let resolvedEnvironment = "";
  switch (env) {
 // case statements for determining whether this is dev, test, stage, or prod
  }
  return resolvedEnvironment;
}

export function resolveNgxLoggerConfig() {
  return configurationSubject.getValue().logging;
}

- app.module.ts - সহজ বোঝার জন্য ছিটানো

মজার ব্যাপার! NGXLogger এর পুরানো সংস্করণগুলির জন্য আপনাকে লগগারমডিউল.ফরট () এর মধ্যে কোনও বস্তুতে পাস করতে হবে। আসলে লগারমডুল এখনও করে! এনজিএক্সলগার দয়া করে লগারকনফাইগকে প্রকাশ করে যা আপনি সেটআপের জন্য একটি ফ্যাক্টরি ফাংশন ব্যবহার করার অনুমতি দিয়ে ওভাররাইড করতে পারেন।

import { resolveEnvironment, resolveNgxLoggerConfig, resolveSomethingElse } from './environment-resolvers';
import { LoggerConfig } from 'ngx-logger';
@NgModule({
    modules: [
        SomeModule.forRoot(resolveSomethingElse)
    ],
    providers:[
        {
            provide: ENVIRONMENT,
            useFactory: resolveEnvironment
        },
        { 
            provide: LoggerConfig,
            useFactory: resolveNgxLoggerConfig
        }
    ]
})
export class AppModule

সংযোজন

আমি কীভাবে আমার এপিআই url তৈরির সমাধান করেছি?

আমি প্রতিটি ইউআরএল একটি মন্তব্যের মাধ্যমে কী করেছে তা বুঝতে সক্ষম হতে চেয়েছিলাম এবং জাভাস্ক্রিপ্টের (আইএমও) তুলনায় টাইপস্ক্রিপ্টের সবচেয়ে বড় শক্তি যেহেতু টাইপচেকিং চেয়েছিল। আমি অন্যান্য ডেভসদের জন্য নতুন এন্ডপয়েন্টগুলি যুক্ত করতে একটি অভিজ্ঞতা তৈরি করতে চেয়েছিলাম, এবং এপিএস যেটি যতটা সম্ভব নির্বিঘ্ন ছিল।

আমি একটি ক্লাস তৈরি করেছি যা পরিবেশ (ডিভ, টেস্ট, স্টেজ, প্রোড, "" এবং ইত্যাদি) নেবে এবং এই মানটি একাধিক ক্লাসে পাস করেছে [1-N] যার কাজ প্রতিটি API সংকলনের জন্য বেস url তৈরি করা create । প্রতিটি এপিআইক্লিকেশন এপিআইয়ের প্রতিটি সংগ্রহের জন্য বেস url তৈরির জন্য দায়বদ্ধ responsible আমাদের নিজস্ব এপিআই, বিক্রেতার এপিআই বা একটি বাহ্যিক লিঙ্ক হতে পারে। এই শ্রেণিটি এটির প্রতিটি পরবর্তী এপিতে তৈরি বেস url পাস করবে। খালি হাড়ের উদাহরণ দেখতে নীচের কোডটি পড়ুন। একবার সেটআপ হয়ে গেলে, অন্য দেবের পক্ষে এপি ক্লাসে অন্য কোনও স্পর্শ না করেই অন্য একটি শেষ পয়েন্ট যুক্ত করা খুব সহজ।

টিএলডিআর; মেমরি অপ্টিমাইজেশনের জন্য বেসিক ওওপি নীতিগুলি এবং অলস গেটর

@Injectable({
    providedIn: 'root'
})
export class ApiConfig {
    public apis: Apis;

    constructor(@Inject(ENVIRONMENT) private environment: string) {
        this.apis = new Apis(environment);
    }
}

export class Apis {
    readonly microservices: MicroserviceApiCollection;

    constructor(environment: string) {
        this.microservices = new MicroserviceApiCollection(environment);
    }
}

export abstract class ApiCollection {
  protected domain: any;

  constructor(environment: string) {
      const domain = this.resolveDomain(environment);
      Object.defineProperty(ApiCollection.prototype, 'domain', {
          get() {
              Object.defineProperty(this, 'domain', { value: domain });
              return this.domain;
          },
          configurable: true
      });
  }
}

export class MicroserviceApiCollection extends ApiCollection {
  public member: MemberApi;

  constructor(environment) {
      super(environment);
      this.member = new MemberApi(this.domain);
  }

  resolveDomain(environment: string): string {
      return `https://subdomain${environment}.actualdomain.com/`;
  }
}

export class Api {
  readonly base: any;

  constructor(baseUrl: string) {
      Object.defineProperty(this, 'base', {
          get() {
              Object.defineProperty(this, 'base',
              { value: baseUrl, configurable: true});
              return this.base;
          },
          enumerable: false,
          configurable: true
      });
  }

  attachProperty(name: string, value: any, enumerable?: boolean) {
      Object.defineProperty(this, name,
      { value, writable: false, configurable: true, enumerable: enumerable || true });
  }
}

export class MemberApi extends Api {

  /**
  * This comment will show up when referencing this.apiConfig.apis.microservices.member.memberInfo
  */
  get MemberInfo() {
    this.attachProperty("MemberInfo", `${this.base}basic-info`);
    return this.MemberInfo;
  }

  constructor(baseUrl: string) {
    super(baseUrl + "member/api/");
  }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.