Обновление хранилища Ngrx из поля со списком материалов и затем привязка к возвращенным данным хранилища Ngrx - PullRequest
0 голосов
/ 16 марта 2019

Я только начинаю разбираться с Ngrx.Я подключил различные элементы управления, чтобы обновить и затем вернуть данные из моего магазина.Текстовые поля и флажки работают должным образом, однако поля со списком - это другой этаж.Я не могу получить правильное связывание.

Вот проблемы, с которыми я сталкиваюсь:

1) Когда я обновляю значение в поле со списком, моя функция setCurrentBadge запускается дважды

2) Значение, которое я выбрал изсписок в поле со списком <mat-select class="badge-codes-combobox"> не отображается.

3) Функция getCurrentBadge запускается, даже если она находится в хуке жизненного цикла ngInit и страница не перезагружена.

4) Когда я перезагружаю страницу, функция getCurrentBadge запускается, но поле со списком не отображает возвращенное значение.

Что касается кода, мне нужно, чтобы badgeCodeSelected ($ event) запускался только один раз.когда значение поля со списком изменяется.Мне нужно, чтобы [value] = "selectedBadge" отображало выбранное значение, а когда страница перезагружалась, мне нужно комбинированное окно для отображения значения, возвращенного из магазина)

Вот мой код.

    <div class="row">
  <div class="col-md-4">
    <app-declaration-type
    [errorMessage] = "errorMessage$ | async"
    [displayTypes] = "displayTypes$ | async"
    [declarationTypes] = "declarationTypes$ | async"
    [badges] = "badges$ | async"
    [traderReference]= "traderReference$ | async"
    [selectedBadge] = "selectedBadge$ | async"
    (badgeSelected) = "badgeCodeSelected($event)" 
    (checked) = "checkChanged($event)"
    (traderReferenceSet) = "onBlurTraderReferenceChange($event)"
    >
    </app-declaration-type>
  </div>
</div>

@Component({
  selector: 'app-declaration',
  templateUrl: './declaration-shell.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class DeclarationShellComponent implements OnInit {
  errorMessage$: Observable<string>;
  displayTypes$: Observable<boolean>;
  declarationTypes$: Observable<Declarationtype[]>;
  badges$: Observable<Badge[]>;
  selectedDeclarationType$: Observable<string>;
  selectedBadge$: Observable<Badge>;
  traderReference$: Observable<string>;

  constructor(private store: Store<fromDeclaraionType.State>) {}

  ngOnInit() {
    this.store.dispatch(new fromDeclarationTypeActions.LoadDeclarationType());
    this.store.dispatch(new fromDeclarationTypeActions.LoadBadges());

    this.errorMessage$ = this.store.pipe(select(fromDeclaraionType.getError));
    this.displayTypes$ = this.store.pipe(
      select(fromDeclaraionType.getToggleDeclarationTypes)
    );
    this.declarationTypes$ = this.store.pipe(
      select(fromDeclaraionType.getDeclarationTypes)
    );

    this.selectedDeclarationType$ = this.store.pipe(
      select(fromDeclaraionType.getCurrentDeclarationType)
    );

    this.badges$ = this.store.pipe(select(fromDeclaraionType.getBadges));

    this.selectedBadge$ = this.store.pipe(
      select(fromDeclaraionType.getCurrentBadge),
      tap(x => console.log('About to fetch current badge from store {0}', x))
    );

    this.traderReference$ = this.store.pipe(
      select(fromDeclaraionType.getTraderReference)
    );
  }

  checkChanged(value: boolean): void {
    console.log('About to dispatch toggle Display Declaration Types');
    this.store.dispatch(
      new fromDeclarationTypeActions.ToggleDeclarationTypes(value)
    );
  }

  onBlurTraderReferenceChange(value: string) {
    console.log('About to dispatch Set Trader Reference');
    this.store.dispatch(
      new fromDeclarationTypeActions.SetTraderReference(value)
    );
  }

  badgeCodeSelected(value: Badge) {
    console.log('About to dispatch Set Current Badge');
    console.log(value);
    this.store.dispatch(new fromDeclarationTypeActions.SetCurrentBadge(value));
  }
}

 <div class="declaration-type">
  <mat-accordion>
    <mat-expansion-panel
      [expanded]="displayTypes === true"
      (opened)="(displayTypes === true)"
    >
      <mat-expansion-panel-header
        [collapsedHeight]="customCollapsedHeight"
        [expandedHeight]="customExpandedHeight"
      >
        <mat-panel-title> <h4>Declaration Type</h4> </mat-panel-title>
        <label>
          <input
            class="form-check-input"
            type="checkbox"
            (change)="checkChanged($event.target.checked)"
            [checked]="displayTypes"
          />
          Display Types?
        </label>
      </mat-expansion-panel-header>

      <div class="controls-wrapper">
        <div class="flex-container">
          <div class="flex-item-declarationType">
            <label class="field-label labelAlignment">
              Decln Type [01]:
              <mat-select class="declaration-type-combobox" [value]="selectedDeclarationType">
                <mat-option
                  *ngFor="let declarationType of declarationTypes"
                  [value]="declarationType?.value"

                >
                  {{ declarationType.value }}
                </mat-option>
              </mat-select>
            </label>
          </div>
          <div class="flex-item-badgeCode">
            <label class="field-label labelAlignment">
              Badge Codes:
              <mat-select class="badge-codes-combobox" [value]="selectedBadge" >
                <mat-option (onSelectionChange)="badgeCodeSelected(badge)"
                  *ngFor="let badge of badges"
                  [value]="badge?.code">
                 <div>{{ badge.code }} - {{ badge.name }}</div>
                </mat-option>
              </mat-select>
            </label>
          </div>
        </div>
        <div class="flex-container">
          <div class="flex-item-traderReference">
            <label class="field-label labelAlignment">
              Trader Reference [07]:
              <input
                matInput
                type="text"
                [(ngModel)]="traderReference"
                class="trader-reference-inputBox"
                (blur)="onTraderReferenceSet(traderReference)"
              />
              <button
                mat-button
                *ngIf="traderReference"
                matSuffix
                mat-icon-button
                aria-label="Clear"
                (click)="traderReferenceValue = ''"
              >
                <mat-icon>close</mat-icon>
              </button>
            </label>
          </div>
        </div>
      </div>
    </mat-expansion-panel>
  </mat-accordion>
</div>

@Component({
  selector: 'app-declaration-type',
  templateUrl: './declaration-type.component.html',
  styleUrls: ['./declaration-type.component.scss']
})
export class DeclarationTypeComponent implements OnInit {
  customCollapsedHeight = '40px';
  customExpandedHeight = '40px';

  @Input() errorMessage: string;
  @Input() displayTypes: boolean;
  @Input() declarationTypes: Declarationtype[];
  @Input() badges: Badge[];
  @Input() selectedDeclarationType: string;
  @Input() selectedBadge: Badge;
  @Input() traderReference: string;

  @Output() checked = new EventEmitter<boolean>();
  @Output() declarationTypeSelected = new EventEmitter<string>();
  @Output() badgeSelected = new EventEmitter<Badge>();
  @Output() traderReferenceSet = new EventEmitter<string>();

  constructor() {}

  ngOnInit(): void {}

  checkChanged(value: boolean): void {
    this.checked.emit(value);
  }

  badgeCodeSelected(value: Badge) {
    this.badgeSelected.emit(value);
  }

  onTraderReferenceSet(value: string) {
    this.traderReferenceSet.emit(value);
  }
}

1 Ответ

0 голосов
/ 19 марта 2019

Это было бы немного сдвигом для вас, но я хотел бы поделиться с вами тем, что у меня есть библиотека, которая, помимо прочего, имеет встроенные директивы для привязки элементов управления формы к хранилищу.Большой сдвиг в том, что вам нужно будет построить StoreObject вместо использования селектора, и вы не будете писать или обрабатывать какие-либо действия.

Библиотека называется ng-app-state, а ключ к привязке к элементам управления формы находится в директиве nasModel.Я дам вам идею ниже.

Допустим, значение для вашего флажка находится в магазине в таком месте:

class DeclarationTypeState {
  badgeCode: string;
}

Тогда вы будете использовать его следующим образом:

@Component({
  template: `
    <mat-select [nasModel]="badgeCodeStore">
      <mat-option ...></mat-option>
    </mat-select>
  `,
})
export class DeclarationTypeComponent {
  badgeCodeStore: StoreObject<string>;

  constructor(myStore: MyStore) {
    this.badgeCodeStore = myStore('keyForDeclarationTypeState')('badgeCode');
  }
}

Это выполнит двустороннюю привязку к вашему магазину, чтобы mat-select оставался синхронизированным с магазином, и отредактирует значение в магазине, когда пользователь его изменит.

...