অ্যাঙ্গুলারজেএস এর মতো @ ইনপুট হিসাবে শিশু উপাদানগুলিতে কৌণিক পাস কলব্যাক ফাংশন


227

অ্যাঙ্গুলারজেএস এর এমন ও প্যারামিটার রয়েছে যেখানে আপনি কোনও নির্দেশকে কলব্যাক দিতে পারতেন (যেমন কলিগ্যাক্সের অ্যাঙ্গুলারজেএস উপায় an @Inputএকটি কৌণিক উপাদানটির জন্য কলব্যাক পাস করা কি সম্ভব (নীচের মতো কিছু)? যদি না হয় তবে নিকটতম জিনিসটি কী হবে? কৌণিক জেএস করে?

@Component({
    selector: 'suggestion-menu',
    providers: [SuggestService],
    template: `
    <div (mousedown)="suggestionWasClicked(suggestion)">
    </div>`,
    changeDetection: ChangeDetectionStrategy.Default
})
export class SuggestionMenuComponent {
    @Input() callback: Function;

    suggestionWasClicked(clickedEntry: SomeModel): void {
        this.callback(clickedEntry, this.query);
    }
}


<suggestion-menu callback="insertSuggestion">
</suggestion-menu>

6
ভবিষ্যতের পাঠকদের জন্য @Inputপরামর্শ দেওয়া হয়েছে আমার কোডটি স্প্যাগেটি বানানো এবং বজায় রাখা সহজ নয় .. @Outputগুলি আমি যা চাই তা করার অনেক বেশি প্রাকৃতিক উপায়। ফলস্বরূপ আমি স্বীকৃত উত্তরটি পরিবর্তন করেছি
Michail Michailidis

@ আইএনএস প্রশ্ন অ্যাঙ্গুলারজেএস এর অনুরূপ কৌণিক কিছুতে কীভাবে হয় সে সম্পর্কে? শিরোনাম বিভ্রান্তিকর কেন?
মিশেল মাইখাইলিডিস

কৌণিকটি AngularJS থেকে খুব আলাদা। কৌণিক 2+ কেবল কৌণিক।
ইয়ান এস

1
আপনার শিরোনাম স্থির করে;)
ইয়ান এস

1
@ আইএনএস ধন্যবাদ! এখন প্রশ্নটি কৌণিক জেসের সম্পর্কে - যদিও আপনি ট্যাগ যুক্ত করেছেন।
মিশেল মাইখাইলিডিস

উত্তর:


296

আমি মনে করি এটি একটি খারাপ সমাধান। আপনার সাথে উপাদান মধ্যে একটি ফাংশন পাস করতে চান, @Input(), @Output()প্রসাধক আপনি যা খুঁজছেন হয়।

export class SuggestionMenuComponent {
    @Output() onSuggest: EventEmitter<any> = new EventEmitter();

    suggestionWasClicked(clickedEntry: SomeModel): void {
        this.onSuggest.emit([clickedEntry, this.query]);
    }
}

<suggestion-menu (onSuggest)="insertSuggestion($event[0],$event[1])">
</suggestion-menu>

45
সুনির্দিষ্টভাবে আপনি ফাংশনটি পাস করছেন না বরং শ্রোতার ইভেন্ট শ্রোতাদের আউটপুটটিতে জড়িয়ে রাখছেন। এটি কেন কাজ করে তা বোঝার জন্য সহায়ক।
জেনস

13
এটি দুর্দান্ত পদ্ধতি, তবে এই উত্তরটি পড়ার পরে আমি অনেক প্রশ্ন রেখেছি। আমি আশা করছিলাম যে এটি আরও গভীরতর হবে বা বর্ণনা করার জন্য একটি লিঙ্ক সরবরাহ করবে @Outputএবং EventEmitter। সুতরাং, আগ্রহীদের জন্য @ আউটপুট এর কৌণিক ডকুমেন্টেশন এখানে রয়েছে ।
ওয়ান্ডারার

9
এটি একমুখী বাইন্ডিংয়ের জন্য সূক্ষ্ম। আপনি সন্তানের ইভেন্টে হুকআপ করতে পারেন। তবে আপনি সন্তানের কাছে কলব্যাক ফাংশনটি পাস করতে পারবেন না এবং এটিকে কলব্যাকের ফেরতের মূল্য বিশ্লেষণ করতে দিন। নীচের উত্তর এটি অনুমতি দেয়।
রুক

3
"আমি মনে করি এটি একটি খারাপ সমাধান" হওয়ার পরিবর্তে কেন একটি উপায় বনাম অন্য পথে পছন্দ করা যায় সে সম্পর্কে আমি আরও ব্যাখ্যা আশা করব expect
ফিদান হাকাজ

6
সম্ভবত 80% কেসের জন্য ভাল, তবে যখন কোনও শিশু উপাদান কলব্যাকের উপস্থিতি আছে কিনা তা শর্তসাপেক্ষে ভিজ্যুয়ালাইজেশন চায় not
জন ফ্রিম্যান

115

হালনাগাদ

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

আসল উত্তর

হ্যাঁ বাস্তবে এটি হ'ল তবে আপনি এটি সঠিকভাবে বাদ দিয়েছেন তা নিশ্চিত করতে চাইবেন op এর জন্য আমি কোনও সম্পত্তি ব্যবহার করেছি তা নিশ্চিত করার জন্য thisআমি এটি কী চাই।

@Component({
  ...
  template: '<child [myCallback]="theBoundCallback"></child>',
  directives: [ChildComponent]
})
export class ParentComponent{
  public theBoundCallback: Function;

  public ngOnInit(){
    this.theBoundCallback = this.theCallback.bind(this);
  }

  public theCallback(){
    ...
  }
}

@Component({...})
export class ChildComponent{
  //This will be bound to the ParentComponent.theCallback
  @Input()
  public myCallback: Function; 
  ...
}

1
এই কাজ! ধন্যবাদ! আমি চাই যে ডকুমেন্টেশনটি কোথাও
এলো

1
আপনি চাইলে আপনি একটি স্থিতিশীল পদ্ধতি ব্যবহার করতে পারেন, তবে তারপরে আপনার উপাদানটির কোনও সদস্যের অ্যাক্সেস থাকবে না। সুতরাং সম্ভবত আপনার ব্যবহারের ক্ষেত্রে না। তবে হ্যাঁ, Parent -> Child
আপনারও

3
দুর্দান্ত উত্তর! যদিও বাঁধাই হয় আমি সাধারণত ফাংশনটির নাম পরিবর্তন করি না। মধ্যে ngOnInitআমি কেবল ব্যবহার করব: this.theCallback = this.theCallback.bind(this)এবং তারপরে আপনি এর theCallbackপরিবর্তে পাশ দিয়ে যেতে পারেন theBoundCallback
জ্যাক

1
@ মিচাইলমিচাইলিডিস হ্যাঁ, আমি আপনার সমাধানের সাথে একমত এবং লোককে আরও ভাল পথে নিয়ে যাওয়ার জন্য একটি উত্তর দিয়ে আমার উত্তরটি আপডেট করেছি। এই এক নজর রাখার জন্য ধন্যবাদ।
SnareChops

7
@ আউটপুট এবং ইভেন্টএমিটার এক উপায় বাঁধাইয়ের জন্য ভাল। আপনি সন্তানের ইভেন্টে হুকআপ করতে পারেন তবে আপনি সন্তানের কাছে কলব্যাক ফাংশনটি পাস করতে পারবেন না এবং এটি কলব্যাকের ফেরতের মান বিশ্লেষণ করতে দিন। এই উত্তর যে অনুমতি দেয়।
রুক

31

SnareChops দেওয়া উত্তরের একটি বিকল্প।

একই প্রভাব পেতে আপনি নিজের টেমপ্লেটে .bind (এটি) ব্যবহার করতে পারেন। এটি পরিষ্কার হিসাবে নাও হতে পারে তবে এটি কয়েক লাইনের সংরক্ষণ করে। আমি বর্তমানে কৌনিক ২.৪.০ এ আছি

@Component({
  ...
  template: '<child [myCallback]="theCallback.bind(this)"></child>',
  directives: [ChildComponent]
})
export class ParentComponent {

  public theCallback(){
    ...
  }
}

@Component({...})
export class ChildComponent{
  //This will be bound to the ParentComponent.theCallback
  @Input()
  public myCallback: Function; 
  ...
}

2
অন্যরা যেমন টেম্পলেটে বাইন্ড (এটি) মন্তব্য করেছেন তা কোথাও নথিভুক্ত নেই যাতে এটি ভবিষ্যতে অবনমিত / অসমর্থিত হয়ে উঠতে পারে। প্লাস আবার @Inputকোডটি স্প্যাগেটি হয়ে উঠছে এবং @Outputফলাফলকে আরও প্রাকৃতিক / অপরিবর্তিত প্রক্রিয়াতে ব্যবহার করছে
মিশেল মাইখাইলিডিস

1
আপনি যখন টেম্পলেটে বাইন্ড () রাখেন তখন প্রতিটি পরিবর্তন সনাক্তকরণে কৌণিক এই ভাবটি পুনরায় মূল্যায়ন করে। অন্যান্য সমাধান - টেম্পলেটটির বাইরের সাথে বাঁধাই করা - কম সংক্ষিপ্ত, তবে এতে এই সমস্যা নেই।
ক্রিস

প্রশ্ন: .বাইন্ড (এটি) করার সময়, আপনি বাচ্চা বা পিতামাতার সাথে কলব্যাক বাঁধাই পদ্ধতি? আমি মনে করি এটি সন্তানের সাথেই আছে। তবে বিষয়টি হ'ল, যখন বাঁধনটি ডাকা হচ্ছে, এটি সর্বদা শিশুরা ডাকছে, তাই আমি সঠিক হলে এই বাঁধাইটি প্রয়োজনীয় বলে মনে হয় না।
ক্রিসজেড

এটি প্যারেন্ট উপাদানগুলির সাথে আবদ্ধ। এটি করার কারণটি হ'ল যখন কলব্যাক () বলা হচ্ছে তখন এটি সম্ভবত নিজের ভিতরে কিছু করতে চাইবে, এবং যদি "এটি" মূল উপাদান না হয় তবে এটি তার নিজস্ব পদ্ধতি এবং পরিবর্তনশীলগুলিতে পৌঁছতে পারে না আর।
ম্যাক্স

29

কিছু ক্ষেত্রে, আপনার পিতামাতার উপাদান দ্বারা সম্পাদন করার জন্য ব্যবসায়ের যুক্তি প্রয়োজন হতে পারে। নীচের উদাহরণে আমাদের একটি শিশু উপাদান রয়েছে যা পিতামাতার উপাদান দ্বারা সরবরাহিত যুক্তির উপর নির্ভর করে সারণী সারিটি সরবরাহ করে:

@Component({
  ...
  template: '<table-component [getRowColor]="getColor"></table-component>',
  directives: [TableComponent]
})
export class ParentComponent {

 // Pay attention on the way this function is declared. Using fat arrow (=>) declaration 
 // we can 'fixate' the context of `getColor` function
 // so that it is bound to ParentComponent as if .bind(this) was used.
 getColor = (row: Row) => {
    return this.fancyColorService.getUserFavoriteColor(row);
 }

}

@Component({...})
export class TableComponent{
  // This will be bound to the ParentComponent.getColor. 
  // I found this way of declaration a bit safer and convenient than just raw Function declaration
  @Input('getRowColor') getRowColor: (row: Row) => Color;

  renderRow(){
    ....
    // Notice that `getRowColor` function holds parent's context because of a fat arrow function used in the parent
    const color = this.getRowColor(row);
    renderRow(row, color);
  }
}

সুতরাং, আমি এখানে 2 টি জিনিস প্রদর্শন করতে চেয়েছিলাম:

  1. সঠিক প্রসঙ্গ ধরে রাখার জন্য .bind (এটি) এর পরিবর্তে ফ্যাট এ্যার (=>) ফাংশন;
  2. শিশু উপাদানটিতে কলব্যাক ফাংশনের টাইপসেফের ঘোষণা।

1
ব্যবহারের প্রতিস্থাপনের জন্য চর্বিযুক্ত তীর ব্যবহারের দুর্দান্ত ব্যাখ্যা.bind(this)
টিওয়াইএমজি

6
ব্যবহারের টিপ: নিশ্চিত করে রাখুন [getRowColor]="getColor"এবং না [getRowColor]="getColor()";-)
সাইমন_উইভার

খুশী হলাম। আমি ঠিক এটিই খুঁজছিলাম। সহজ এবং কার্যকর।
BrainSlugs83

7

উদাহরণ হিসাবে, আমি লগইন মডেল উইন্ডোটি ব্যবহার করছি, যেখানে মোডাল উইন্ডোটি প্যারেন্ট, লগইন ফর্মটি শিশু এবং লগইন বোতামটি মডেল পিতামাতার ঘনিষ্ঠ ফাংশনে ফিরে আসে calls

পিতামাতার মোডালটিতে মোডালটি বন্ধ করার জন্য ফাংশন রয়েছে। এই পিতামাতাই লগইন শিশু উপাদানটিতে ঘনিষ্ঠ ফাংশনটি পাস করে।

import { Component} from '@angular/core';
import { LoginFormComponent } from './login-form.component'

@Component({
  selector: 'my-modal',
  template: `<modal #modal>
      <login-form (onClose)="onClose($event)" ></login-form>
    </modal>`
})
export class ParentModalComponent {
  modal: {...};

  onClose() {
    this.modal.close();
  }
}

চাইল্ড লগইন উপাদানটি লগইন ফর্ম জমা দেওয়ার পরে, এটি পিতামাতার কলব্যাক ফাংশনটি ব্যবহার করে পিতামাতার মডেলটি বন্ধ করে দেয়

import { Component, EventEmitter, Output } from '@angular/core';

@Component({
  selector: 'login-form',
  template: `<form (ngSubmit)="onSubmit()" #loginForm="ngForm">
      <button type="submit">Submit</button>
    </form>`
})
export class ChildLoginComponent {
  @Output() onClose = new EventEmitter();
  submitted = false;

  onSubmit() {
    this.onClose.emit();
    this.submitted = true;
  }
}

7

ম্যাক্স ফাহাল যে উত্তরটি দিয়েছিল তার বিকল্প।

আপনি কলব্যাক ফাংশনটিকে প্যারেন্ট উপাদানগুলিতে একটি তীর ফাংশন হিসাবে সংজ্ঞায়িত করতে পারেন যাতে আপনার এটির সাথে আবদ্ধ হওয়ার প্রয়োজন নেই।

@Component({
  ...
  // unlike this, template: '<child [myCallback]="theCallback.bind(this)"></child>',
  template: '<child [myCallback]="theCallback"></child>',
  directives: [ChildComponent]
})
export class ParentComponent {

   // unlike this, public theCallback(){
   public theCallback = () => {
    ...
  }
}

@Component({...})
export class ChildComponent{
  //This will be bound to the ParentComponent.theCallback
  @Input()
  public myCallback: Function; 
  ...
}


5

টেমপ্লেটের অভ্যন্তরে .bind ব্যবহার করে যুক্তি সহ পদ্ধতিটি পাস করা

@Component({
  ...
  template: '<child [action]="foo.bind(this, 'someArgument')"></child>',
  ...
})
export class ParentComponent {
  public foo(someParameter: string){
    ...
  }
}

@Component({...})
export class ChildComponent{

  @Input()
  public action: Function; 

  ...
}

আপনার উত্তরটি কি মূলত একই নয়: stackoverflow.com/a/42131227/986160 ?
মিশেল মাইখাইলিডিস

এই মন্তব্যটি উত্তর stackoverflow.com/questions/35328652/...
Shogg

0

পর্যবেক্ষণযোগ্য প্যাটার্ন ব্যবহার করুন। আপনি পর্যবেক্ষণযোগ্য মান (বিষয় নয়) ইনপুট প্যারামিটারে রাখতে পারেন এবং এটি প্যারেন্ট উপাদান থেকে পরিচালনা করতে পারেন। আপনার কলব্যাক ফাংশন দরকার নেই।

উদাহরণ দেখুন: https://stackoverflow.com/a/49662611/4604351


আপনি দয়া করে একটি কাজের উদাহরণ দিয়ে বর্ণনা করতে পারেন?
মিশেল মাইখাইলিডিস

0

আরেকটি বিকল্প।

ওপি কলব্যাক ব্যবহার করার জন্য একটি উপায় জিজ্ঞাসা করেছিল। এক্ষেত্রে তিনি বিশেষত এমন একটি ফাংশনকে উল্লেখ করছেন যা কোনও ইভেন্ট প্রক্রিয়া করে (তার উদাহরণে: একটি ক্লিক ইভেন্ট), যা @ সার্জিনহোর পরামর্শ অনুযায়ী গৃহীত উত্তর হিসাবে বিবেচিত হবে: সাথে @Outputএবং EventEmitter

তবে, কলব্যাক এবং ইভেন্টের মধ্যে পার্থক্য রয়েছে: একটি কলব্যাকের সাহায্যে আপনার সন্তানের উপাদানটি পিতামাতার কাছ থেকে কিছু প্রতিক্রিয়া বা তথ্য অর্জন করতে পারে তবে কোনও ইভেন্ট কেবল তা জানাতে পারে যে কোনও প্রতিক্রিয়া প্রত্যাশা ছাড়াই কিছু ঘটেছিল।

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

উদাহরণ

ধরা যাক আপনার কাছে একটি জেনেরিক উপাদান রয়েছে যা উপাদানগুলির একটি তালিকার উপর পরিচালনা করে - আইডি, নাম} যা আপনি এই ক্ষেত্রগুলি সহ আপনার সমস্ত ডাটাবেস টেবিলের সাথে ব্যবহার করতে চান। এই উপাদানটি করা উচিত:

  • উপাদানগুলির একটি ব্যাপ্তি (পৃষ্ঠা) পুনরুদ্ধার করুন এবং তাদের একটি তালিকাতে দেখান
  • একটি উপাদান সরানোর অনুমতি দিন
  • অবহিত করুন যে কোনও উপাদান ক্লিক করা হয়েছে, তাই পিতামাতারা কিছু পদক্ষেপ নিতে পারেন।
  • উপাদানগুলির পরবর্তী পৃষ্ঠাটি পুনরুদ্ধার করার অনুমতি দিন।

শিশু উপাদান

সাধারণ বাইন্ডিং ব্যবহার করে আমাদের 1 @Input()এবং 3 @Output()পরামিতি প্রয়োজন (তবে পিতামাতার কোনও প্রতিক্রিয়া ছাড়াই)। যাত্রা। <list-ctrl [items]="list" (itemClicked)="click($event)" (itemRemoved)="removeItem($event)" (loadNextPage)="load($event)" ...>, তবে একটি ইন্টারফেস তৈরি করার জন্য আমাদের কেবল একটির প্রয়োজন হবে @Input():

import {Component, Input, OnInit} from '@angular/core';

export interface IdName{
  id: number;
  name: string;
}

export interface IListComponentCallback<T extends IdName> {
    getList(page: number, limit: number): Promise< T[] >;
    removeItem(item: T): Promise<boolean>;
    click(item: T): void;
}

@Component({
    selector: 'list-ctrl',
    template: `
      <button class="item" (click)="loadMore()">Load page {{page+1}}</button>
      <div class="item" *ngFor="let item of list">
          <button (click)="onDel(item)">DEL</button>
          <div (click)="onClick(item)">
            Id: {{item.id}}, Name: "{{item.name}}"
          </div>
      </div>
    `,
    styles: [`
      .item{ margin: -1px .25rem 0; border: 1px solid #888; padding: .5rem; width: 100%; cursor:pointer; }
      .item > button{ float: right; }
      button.item{margin:.25rem;}
    `]
})
export class ListComponent implements OnInit {
    @Input() callback: IListComponentCallback<IdName>; // <-- CALLBACK
    list: IdName[];
    page = -1; 
    limit = 10;

    async ngOnInit() {
      this.loadMore();
    }
    onClick(item: IdName) {
      this.callback.click(item);   
    }
    async onDel(item: IdName){ 
        if(await this.callback.removeItem(item)) {
          const i = this.list.findIndex(i=>i.id == item.id);
          this.list.splice(i, 1);
        }
    }
    async loadMore(){
      this.page++;
      this.list = await this.callback.getList(this.page, this.limit); 
    }
}

মূল উপাদান Comp

এখন আমরা প্যারেন্টে তালিকার উপাদানটি ব্যবহার করতে পারি।

import { Component } from "@angular/core";
import { SuggestionService } from "./suggestion.service";
import { IdName, IListComponentCallback } from "./list.component";

type Suggestion = IdName;

@Component({
  selector: "my-app",
  template: `
    <list-ctrl class="left" [callback]="this"></list-ctrl>
    <div class="right" *ngIf="msg">{{ msg }}<br/><pre>{{item|json}}</pre></div>
  `,
  styles:[`
    .left{ width: 50%; }
    .left,.right{ color: blue; display: inline-block; vertical-align: top}
    .right{max-width:50%;overflow-x:scroll;padding-left:1rem}
  `]
})
export class ParentComponent implements IListComponentCallback<Suggestion> {
  msg: string;
  item: Suggestion;

  constructor(private suggApi: SuggestionService) {}

  getList(page: number, limit: number): Promise<Suggestion[]> {
    return this.suggApi.getSuggestions(page, limit);
  }
  removeItem(item: Suggestion): Promise<boolean> {
    return this.suggApi.removeSuggestion(item.id)
      .then(() => {
        this.showMessage('removed', item);
        return true;
      })
      .catch(() => false);
  }
  click(item: Suggestion): void {
    this.showMessage('clicked', item);
  }
  private showMessage(msg: string, item: Suggestion) {
    this.item = item;
    this.msg = 'last ' + msg;
  }
}

মনে রাখবেন যে, <list-ctrl>পায় this(পিতা বা মাতা উপাদান) কলব্যাক অবজেক্ট হিসেবে। একটি অতিরিক্ত সুবিধা হ'ল এটি পিতামাত্ত উদাহরণটি প্রেরণের দরকার নেই, এটি কোনও পরিষেবা বা কোনও বস্তু হতে পারে যা ইন্টারফেস প্রয়োগ করে যদি আপনার ব্যবহারের ক্ষেত্রে এটি অনুমতি দেয়।

পুরো উদাহরণটি এই স্ট্যাকব্লিটজে রয়েছে


-3

বর্তমান উত্তরটি এখানে সরল করা যেতে পারে ...

@Component({
  ...
  template: '<child [myCallback]="theCallback"></child>',
  directives: [ChildComponent]
})
export class ParentComponent{
  public theCallback(){
    ...
  }
}

@Component({...})
export class ChildComponent{
  //This will be bound to the ParentComponent.theCallback
  @Input()
  public myCallback: Function; 
  ...
}

সুতরাং স্পষ্টভাবে আবদ্ধ করার প্রয়োজন নেই?
মিশেল মাইখাইলিডিস

3
ছাড়া .bind(this)তারপর thisকলব্যাক ভেতরে হতে হবে windowব্যাপার আপনার ব্যবহার কেস উপর নির্ভর করে নাও করতে পারেন যা। তবে আপনার যদি thisকলব্যাকে কিছু থাকে তবে .bind(this)তা প্রয়োজনীয়। আপনি যদি না করেন তবে এই সরলীকৃত সংস্করণটি হল যাওয়ার উপায়।
SnareChops

3
আমি সবসময় কলব্যাকটিকে উপাদানটির সাথে আবদ্ধ করার পরামর্শ দিচ্ছি, কারণ শেষ পর্যন্ত আপনি thisকলব্যাক ফাংশনের অভ্যন্তরে ব্যবহার করবেন । এটি কেবল ত্রুটিযুক্ত প্রবণ।
আলেকজান্দ্রে জঙ্গলস

এটি একটি কৌণিক 2 অ্যান্টিপ্যাটার্নের উদাহরণ।
সার্গিনহো

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