HTML-шаблон не обновляется, пока я не вызову detectChanges () с использованием changeDetection onpush - PullRequest
0 голосов
/ 03 мая 2018

У меня есть угловой компонент, использующий обнаружение изменений при нажатии. Компонент имеет входные данные, которые изменяются компонентом при обновлении маршрута. Если я назначу ввод новой ссылке и изменим ее, значение в шаблоне не будет обновлено. Я думал, что до тех пор, пока вы назначаете новый объект, изменение будет обнаружено, но это не произойдет, если я не вызову deteChanges () для ChangeDetectorRef.

@Component({
    selector: 'app-nav-links',
    templateUrl: './nav-links.component.html',
    styleUrls: ['./nav-links.component.less'],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class NavLinksComponent implements OnInit {
    @Input() links: Link[] = [];

    private currentPath: string;

    constructor(private router: Router,
                private route: ActivatedRoute,
                private cdr: ChangeDetectorRef) { }

    ngOnInit() {
        this.router.events.subscribe(() => {
            this.updateActiveRoute();
        });
    }

    private updateActiveRoute() {
        this.currentPath = this.route.snapshot.children[0].routeConfig.path;

        this.links = [...this.links].map(link => {
            link.active = link.url === this.currentPath;
            return link;
        });

        // Why is this required if I am already using the spread operator?
        this.cdr.detectChanges();
    }
}

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

Обнаружение изменений происходит всякий раз, когда происходит событие браузера (или угловое событие). В этом случае происходит обнаружение изменений. Однако проблема в том, что исходная ссылка, исходящая от родительского компонента, фактически не изменилась (она изменилась с точки зрения дочернего компонента).

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

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

Чтобы синхронизировать привязку, настройте двустороннюю привязку с помощью EventEmitter:

export class NavLinksComponent implements OnInit {
    @Input() links: Link[] = [];
    @Output() linksChange: EventEmitter<Link[]>;

    constructor() {
        this.linksChange = new EventEmitter<Link[]>();
    }

    ngOnInit() {
       this.router.events.subscribe(() => {
           this.updateActiveRoute();

       });
    }
    private updateActiveRoute() {
        this.currentPath = this.route.snapshot.children[0].routeConfig.path;

        this.links = [...this.links].map(link => {
            link.active = link.url === this.currentPath;
            return link;
        });
        // notify the parent component that the reference has changed
        this.linksChange.next(this.links);
    }
 }

В шаблоне вызывающего компонента настройте двустороннюю привязку, чтобы при изменении внутренней ссылки уведомлять родительский компонент также об обновлении своей ссылки:

<app-nav-links [(links)]="links" />

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

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

0 голосов
/ 03 мая 2018

Проблема заключается в обнаружении изменений на вложенных объектах или, скорее, в их отсутствии. Одним из самых простых решений является JSON.parse(JSON.stringify()) ваш объект перед установкой ссылок и пути:

    this.currentPath = JSON.parse(JSON.stringify(this.route.snapshot.children[0].routeConfig.path));

    this.links = JSON.parse(JSON.stringify([...this.links].map(link => {
        link.active = link.url === this.currentPath;
        return link;
    })));

Что является изменением верхнего уровня вашего объекта, и автоматически вносит изменение. Другой вариант - proc вручную с ChangeDetectorRef, который выполняет полное сканирование объекта и замечает изменения (как вы реализовали).

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

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