угловое расположение 5: расположение динамических компонентов
Я хочу поменять позиции динамически размещенных компонентов внутри представления.
т.е. я динамически создавал компоненты с id = 1 и 2, как показано на рисунке.
теперь мне нужно обменивать позиции обоих компонентов, но как?
Одна вещь, которую я знаю (только теоретически), - это местоположение, которое может быть изменено посредством метода перемещения внутри 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);