Angular 7 [отключен] не обнаруживает изменения при изменении значений свойств вложенного объекта - PullRequest
0 голосов
/ 11 января 2019

Мне нужно написать общую функцию, которая будет включать / отключать кнопки в зависимости от условий внутри JSON.

JSON:

    {
        PURCHASE_LIEN: {
          LABEL: 'PURCHASE LIEN',
          DISABLE: true,
          CONDITION: [
            {
              ReviewPurchaseDecisionStatus: true,
              PurchaseDecisionStatus: false
            },
            {
              ReviewPurchaseDecisionStatus: true,
              'ReviewPurchaseDecision.Status': 'NOT QUALIFIED'
            }
          ]
        },
        NOT_QUALIFIED: {
          LABEL: 'NOT QUALIFIED',
          DISABLE: true,
          CONDITION: [
            {
              ReviewPurchaseDecisionStatus: true,
              PurchaseDecisionStatus: false
            },
            {
              ReviewPurchaseDecisionStatus: true,
              'ReviewPurchaseDecision.Status': 'PURCHASED'
            }
          ]
        }
  }

В JSON у меня есть две кнопки "PURCHASE_LIEN" и "NOT_QUALIFIED". Обе функции имеют массив условий, основанных на условии, кнопка должна быть включена / отключена с помощью свойства «DISABLE».

VALIDATION.SERVICE.TS

Приведенная ниже функция устанавливает свойство DISABLE кнопки на основе условий для объекта (selectedRow).

public disableButton(buttonContainer: any, buttonID: string, selectedRow: any) {
    let status = true;
    for (let i = 0; i < buttonContainer[buttonID]['CONDITION'].length; i++) {
      const condition = buttonContainer[buttonID]['CONDITION'][i];
      for (const conditionName in condition) {
        if (condition[conditionName] !== selectedRow[condition]) {
          status = false;
        }
      }
      if (status) {
        buttonContainer[buttonID].DISABLE = false;
        break;
      } else {
        buttonContainer[buttonID].DISABLE = true;
      }

    }

    return buttonContainer;
  }

app.component.html

 <div class="col-12 col-sm-6 col-md-4 col-lg-2">
        <button class="btn btn-primary btn-semi-circle" (click)="showModal('Purchase')"
         [disabled]="disableButton(buttonGroup, 'PURCHASE_LIEN', selectedRowData)">Purchase
          Lien</button>
          <!-- [disabled]="PURCHASE_LIEN_DISABLE" -->
      </div>
      <div class="col-12 col-sm-6 col-md-4 col-lg-2">
        <button class="btn btn-danger btn-semi-circle" (click)="showModal('Not Qualified')"
         [disabled]="disableButton(buttonGroup, 'NOT_QUALIFIED', selectedRowData)">Not
          Qualified</button>
          <!-- [disabled]="NOT_QUALIFIED_DISABLE" -->
      </div>

app.component.ts

export class ReviewPurchaseDecisionComponent implements OnInit {
  public buttonGroup: any = {
    PURCHASE_LIEN: {
      LABEL: 'PURCHASE LIEN',
      DISABLE: true,
      CONDITION: [
        {
          ReviewPurchaseDecisionStatus: true,
          PurchaseDecisionStatus: false
        },
        {
          ReviewPurchaseDecisionStatus: true,
          'ReviewPurchaseDecision.Status': 'NOT QUALIFIED'
        }
      ]
    },
    NOT_QUALIFIED: {
      LABEL: 'NOT QUALIFIED',
      DISABLE: true,
      CONDITION: [
        {
          ReviewPurchaseDecisionStatus: true,
          PurchaseDecisionStatus: false
        },
        {
          ReviewPurchaseDecisionStatus: true,
          'ReviewPurchaseDecision.Status': 'PURCHASED'
        }
      ]
    }
  };

  constructor(
    public router: Router,
    public validation: ValidationService,
    private fb: FormBuilder,
    private http: HttpHelperService,
    private myMonitoringService: MyMonitoringService,
    private authentication: AuthenticationService,
    private sessionService: SessionService,
    public dialogService: DialogServiceService,
    private caseService: CaseService,
    private cookieService: CookieService
  ) {}

  disableButton(buttonContainer: any, buttonID: string, selectedRow: any) {
    this.buttonGroup = this.validation.disableButton(
      buttonContainer,
      buttonID,
      selectedRow
    );
    return this.buttonGroup[buttonID].DISABLE;
  }
}

Метод disableButton в службе проверки изменяет значение свойства DISABLE на true / false в зависимости от условий, но кнопка не включается. Не обнаруживает изменений

Ответы [ 2 ]

0 голосов
/ 11 января 2019

Я решил эту проблему, создав директиву. Директива будет обращаться к nativeElement кнопки, она включает / отключает кнопку в зависимости от условия в JSON

БТН-disable.directive.ts

import {
  Directive,
  Renderer2,
  ElementRef,
  Input,
  OnChanges
} from '@angular/core';


@Directive({
  selector: '[appBtnDisable]'
})
export class BtnDisableDirective implements OnChanges {
  @Input() buttonContainer: any = {};
  @Input() buttonID = '';
  @Input() condition: any = {};

  constructor(public ele: ElementRef, public renderer: Renderer2) {
    if (this.buttonID) {
      this.disableButton(this.buttonContainer, this.buttonID, this.condition);
    }
  }

  ngOnChanges() {
    if (this.buttonID) {
      this.disableButton(this.buttonContainer, this.buttonID, this.condition);
    }
  }

  public disableButton(
    buttonContainer: any,
    buttonID: string,
    selectedRow: any
  ) {

    for (let i = 0; i < buttonContainer[buttonID]['CONDITION'].length; i++) {
      const condition = buttonContainer[buttonID]['CONDITION'][i];
      let status = true;
      for (const conditionName in condition) {
        if (
          this.convertNulltoUndefined(condition[conditionName]) !== this.evaluate(conditionName, selectedRow)
        ) {
          status = false;
        }
      }

      if (status) {
        this.ele.nativeElement.disabled = false;
        break;
      } else {
        this.ele.nativeElement.disabled = true;
      }
    }
  }



  evaluate(data: string, selectedRow: any): any {
    if (data.split('.').length > 1) {
      const value = 'selectedRow.' + data;
      try {
        return eval(value);
      } catch (error) {
        return undefined;
      }
    } else {
      return selectedRow[data];
    }
  }

  convertNulltoUndefined(data) {
    return (data === null) ? undefined : data;
  }
}

app.component.html

  <button class="btn btn-primary btn-semi-circle" (click)="showModal('Purchase')"
            appBtnDisable [condition]="selectedRowData" [buttonContainer]="buttonGroup" [buttonID]="'PURCHASE_LIEN'">Purchase
              Lien</button>
0 голосов
/ 11 января 2019

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

Для этого угла нет возможности рекурсивно проверять каждое поле вашего объекта и сравнивать его с предыдущим состоянием, чтобы определить, есть ли у вас какие-либо изменения. Этот шаг вызывает дайджест и помечает как грязный. Это очень трудоемкий процесс, поэтому angular делает это в особом случае (список не полный, просто для демонстрации):

  • @ Выход триггерный
  • @ Ввод изменен
  • отправляется событие браузера (щелчок, зависание и т. Д.)
  • таймаут
  • интервал
  • ....

здесь вы изменяете свой объект, вызывая функцию из атрибута [disable] html. Я подозреваю, что этот случай не распространяется на changeDetectionStrategy по умолчанию.

В любом случае угловая команда не рекомендует манипулировать таким объектом. Рекомендуется использовать любой из этих двух подходов: - Избегайте изменения состояния, предпочитайте создавать новый объект и заменять предыдущий. Как этот простой угол должен сделать myPreviousObject !== myNewObject вместо:

if (
    myPreviousObject.prop1 !== myNewObject.prop1 ||
    myPreviousObject.prop2 !== myPreviousObject.prop2 ||
    ....
)
  • Использовать Observable с неизменным состоянием.

для моей демонстрации я использовал второй подход, и здесь вы можете найти простую реализацию:

моя модель:

export interface disableState {
  PURCHASE_LIEN: {
    disable: boolean;
    disable$: BehaviorSubject<boolean>
  };

  NOT_QUALIFIED: {
    disable: boolean;
    disable$: BehaviorSubject<boolean>
  };
}

внутри моего компонента у меня есть такое свойство:

disableState: disableState = {
    NOT_QUALIFIED: { 
      disable: false, 
      disable$: new BehaviorSubject<boolean>(false),
      },
   PURCHASE_LIEN: { 
      disable: false, 
      disable$: new BehaviorSubject<boolean>(false),
      },
  }

и когда я хочу изменить это значение, я могу сделать это так:

/**
 * Call your service like :
 * this.validation.disableButton()
 */
this.disableState['NOT_QUALIFIED'].disable = true;
this.disableState['NOT_QUALIFIED'].disable$.next(true);

живое кодирование

Полный компонент:

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent  {

  disableState: disableState = {
    NOT_QUALIFIED: { 
      disable: false, 
      disable$: new BehaviorSubject<boolean>(false),
      },
   PURCHASE_LIEN: { 
      disable: false, 
      disable$: new BehaviorSubject<boolean>(false),
      },
  }

  showModal(id: string) {
    console.log(`Open modal : ${id}`);
  }


  dummyPropertyChange() {
    /**
     * Call your service like :
     * this.validation.disableButton()
     */
    this.disableState['NOT_QUALIFIED'].disable = true;
    this.disableState['NOT_QUALIFIED'].disable$.next(true);
  }
}

Обратите внимание, что у меня есть переключатель ChangeDetectionStrategy, чтобы запросить angular только для грязной проверки путем простого сравнения объектов (вместо вложенной). С этого момента, если я хочу обновить данные, я должен:

  • изменить данные всей переменной (вместо только вложенного свойства)
  • использовать наблюдаемый для выполнения изменений на временной шкале.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...