У меня есть некоторые блочные компоненты, которые содержат такие компоненты, как этот:

<app-block *ngFor="let block of blocks">
   <div class="header"></div>
   <div class="content">
      <app-list></app-list>
   </div>
</app-block>

Мне нужно переключить .content после нажатия на .header, чтобы иметь возможность открыть один из блоков по умолчанию. Например третий. Также после закрытия блока мне нужно уведомить компонент в другом модуле Angular. Не дочерний компонент.

Я думаю о применении Redux для установки состояний по умолчанию / открытия / закрытия. Это хороший выбор?

-1
Irina 12 Фев 2021 в 18:09

1 ответ

Лучший ответ

Таким образом, в основном логика состоит в том, чтобы хранить идентификаторы открытых ящиков в массиве.

Отправьте идентификатор коробки, которую необходимо открыть.

В редукторе мы будем переключать открытые / закрытые ящики, фильтруя или нажимая идентификатор ящика.

После этого вы можете выбрать openedBlocks из состояния и использовать в компоненте

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

interface BlockModel {
  id: number;
}

// actions 
export const openedBlock = createAction(
  'Opened Box',
  props < {
    boxId: id
  } > ()
);

// state
export const initialBlocksState = {
  blocks: BoxModel[],
  openedBlocks: number[]
  defaultBlock: null,
};

// helpers
function toggleArrayItem(arr, boxId) {
  return arr.includes(boxId) ?
    arr.filter(id => id !== boxId) // remove box
    :
    [...arr, boxId]; // add box
}

// reducer
const blocksReducer = createReducer(
  initialBlocksState,
  // listen openedBlock action
  on(openedBlock, (state, {
    boxId
  }) => {


    // returns new array with toggled boxes
    const openedBlocks = toggleArrayItem(state.openedBlocks, boxId);

    // return new state
    return {
      ...state,
      openedBlocks

    };
  }),

);

Если вы хотите иметь собственное состояние для каждого блока, вы можете использовать преимущество Object Literal.

Но вам нужно будет сначала сериализовать состояние и предоставить другие действия, которые обновят свойство в желаемом блоке.

// models
interface BlockModel {
  id: number;
  opened: true;
  default: false;
}

interface BlocksState {
  id: BlockModel;
}
// state
export const initialBlocksState = {
  blocksState: BlockState
}
// helpers 
function serializeBlocks(blocks: BlocksModel[]): BlockState {
  return blocks.reduce((acc, block) => {
    acc[block.id] = block;
    return acc;
  }, {});
}
// reducer
const blocksReducer = createReducer(
  initialBlocksState,
  on(loadAllBlocks, (state, { blocks }) => {
    return {
      ...state,
      blocksState: serializeBlocks(blocks)
    };
  }),

);
1
Yuriy 12 Фев 2021 в 18:05