угловое расположение 5: расположение динамических компонентов

Я хочу поменять позиции динамически размещенных компонентов внутри представления.

т.е. я динамически создавал компоненты с id = 1 и 2, как показано на рисунке.

enter image description here

теперь мне нужно обменивать позиции обоих компонентов, но как?

Одна вещь, которую я знаю (только теоретически), - это местоположение, которое может быть изменено посредством метода перемещения внутри ViewContainerRef class через объект как viewContainerRef.move(componentRef.hostView, index).

Я попробовал, но позиции не менялись.

@ViewChild(ContainerRefDirective) location: ContainerRefDirective;

let componentFactory = this.factoryResolver.resolveComponentFactory(EntryComponent);
let componentRef = this.location.viewContainerRef.createComponent(componentFactory);

let entryComponent: EntryComponent = componentRef.instance;
// lets say counter is variable that increments its value on new component creation.
entryComponent.Id = ++counter; 

// move method is being called right after a new component is created and placed. 
//this piece of code is in the same method (that is creating the dynamic components)
this.location.viewContainerRef.move(componentRef.hostView, 1);

Я прочитал документацию ViewContainerRef на angular.io и прочитал почти такой же вопрос относительно этой проблемы, но не смог понять или решить эту проблему.

Ответы

Ответ 1

Решил эту проблему.

Что я сделал?

Я изменил значения, вместо того, чтобы менять места расположения компонентов

т.е. я заменил значения 1 <=> 2 и казалось, что компоненты взаимозаменяемы.

Как?

// array to hold the newly created component instances
entryComponents: EntryComponent[] = new Array<EntryComponent>();

Затем вставьте вновь созданный компонент в этот массив

let factoryResolver = this.factoryResolver.resolveComponentFactory(EntryComponent);    
let componentRef = this.location.viewContainerRef.createComponent(factoryResolver);

this.entryComponents.push(componentRef.instance); // getting components' instances

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

Спасибо @ForestG, за это предложение

Ответ 2

Почему бы вам не привязать два динамических компонента к массиву? например, если у вас есть "objectA" и "objectB":

this.renderArray.push(objectA);
..
this.renderArray.push(objectB);

и ваш html выглядит так:

<ng-container *ngFor="let renderObject of renderArray">
   <<you can reference objectA and objectB by using "renderObject.value" etc.>>
</ng-container>

когда вам нужно обменивать свои позиции, вам просто нужно манипулировать массивом, и угловой заботится об остальном:

this.renderArray = this.renderArray.reverse();

Он будет повторно отображать контейнеры ngFor в новом порядке. См. Рабочий пример здесь.

Ответ 3

Я не пробовал, но почитав документацию звучит как move не является правильным методом. Похоже, что перемещение - это "добавление" существующего компонента в представление.

Из документов для detach:

Используйте вместе со вставкой для перемещения представления в текущем контейнере.

Основываясь на этой строке, я бы попытался...

let ref = this.location.viewContainerRef;
ref.detach(ref.indexOf(componentRef.hostView));
ref.insert(componentRef.hostView, 0);

Редактировать. Я создал рабочий пример с использованием примера " Угловой живой" для динамического компонентного загрузчика.

Вот код, относящийся к вопросу:

// ShaneCoder - don't clear so we get multiple ads to demonstrate move.
// viewContainerRef.clear();

// ShaneCoder - only create 4 ads
if (viewContainerRef.length<4) {

    let componentRef = viewContainerRef.createComponent(componentFactory);
    (<AdComponent>componentRef.instance).data = adItem.data;

    // ShaneCoder ad is inserted at the bottom (no index parameter).  Move it up if there are multiple ads.
    if (viewContainerRef.length>=1) {
        // we're not the first ad
        // move new ad to top using detach and insert (the next two lines answer the original question) 
        viewContainerRef.detach(viewContainerRef.indexOf(componentRef.hostView));
        viewContainerRef.insert(componentRef.hostView, 0);
        // comment out the previous two lines to see that ads are inserted at the bottom.
    }
}

Изменить 2

После опубликования последнего редактирования, я не пробовал move. Переключить detach и insert для move и он работает. Пример здесь. Соответствующий код:

viewContainerRef.move(componentRef.hostView, 0);
// comment out the previous two lines to see that ads are inserted at the bottom.

Теперь мне интересно, была ли проблема, с которой вы боролись с move ее нулевой индекс. Чтобы сделать компонент первым в представлении контейнера, вам нужно передать ноль для индекса. Сделать второй проход один и так далее. Таким образом, ваш код будет меняться следующим образом:

this.location.viewContainerRef.move(componentRef.hostView, 0);