Closed jepiqueau closed 5 years ago
It seems that the ion-reorder-group works directly in the DOM so not going through the render process meaning that you must not toggle for the render. So the workaround is to write the delete function directly on the DOM by removing the child of the ion-reoder-group element, so i modified the app-home as follows
import { Component, Element, Prop, State, Listen } from '@stencil/core';
@Component({
tag: 'app-home',
styleUrl: 'app-home.css'
})
export class AppHome {
@Element() el: Element;
@Prop({ connect: 'ion-alert-controller' }) alertCtrl: HTMLIonAlertControllerElement;
@State() toggle: boolean = false;
list:Array<string>;
alert: HTMLIonAlertElement;
reorderGrpEL: HTMLIonReorderGroupElement;
@Listen('ionItemReorder')
async itemReorderHandler(event: CustomEvent) {
let itemToMove:string = this.list.splice(event.detail.from,1)[0];
this.list.splice(event.detail.to,0,itemToMove);
}
componentWillLoad() {
this.list = [
"deer",
"elephant",
"tiger",
"lion",
"eagle"
];
}
componentDidLoad() {
this.reorderGrpEL = this.el.querySelector('#reorder_group');
}
async presentAlert(options: any): Promise<void> {
this.alert = await this.alertCtrl.create(options);
await this.alert.present();
return;
}
async dismissAlert(): Promise<void> {
await this.alert.dismiss();
return;
}
async _deleteCancel() {
await this.dismissAlert();
}
async _deleteConfirm(index:number) {
let children:NodeListOf<HTMLIonItemElement> = this.reorderGrpEL.querySelectorAll('ion-item');
this.reorderGrpEL.removeChild(children[index]);
this.list.splice(index,1)
await this.dismissAlert();
// this.toggle = !this.toggle;
}
async _handleItemClick(button:string,index:number) {
switch (button) {
case 'delete' : {
let options:any = {
header: 'Confirm Delete!',
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'alertcancel',
handler: () => {
this._deleteCancel();
}
}, {
text: 'Start',
cssClass: 'alertdanger',
handler:() => {
this._deleteConfirm(index);
}
}
]
}
await this.presentAlert(options);
break;
}
}
}
render() {
const reorderList = this.list.map((item,index) => {
return [
<ion-item>
<ion-label>{item}</ion-label>
<ion-reorder slot="end"></ion-reorder>
<ion-icon name="trash" slot="end" color="danger" onClick={() => this._handleItemClick('delete',index)}></ion-icon>
</ion-item>
];
});
return [
<ion-header>
<ion-toolbar color="primary">
<ion-title>Home</ion-title>
</ion-toolbar>
</ion-header>,
<ion-content padding>
<p>
Welcome to the PWA Toolkit. You can use this starter to build entire
apps with web components using Stencil and ionic/core! Check out the
README for everything that comes in this starter out of the box and
check out our docs on <a href="https://stenciljs.com">stenciljs.com</a> to get started.
</p>
<ion-button href="/profile/ionic" expand="block">Profile page</ion-button>
<ion-list id="reorder-list" inset lines="inset">
<ion-reorder-group id="reorder_group" disabled={false}>
{reorderList}
</ion-reorder-group>
</ion-list>
</ion-content>
];
}
}
`
``
You must comment the this.toggle = !this.toggle; in the deleteConfirm function otherwise it doesn't work
So this is a restriction meaning that after reordering and deleting you should never go through the render function
I've seen this similar issue. I've reordered my items via redux. On reorder the data is reordered correctly (logged inside redux, and even rendered outside the ion-reorder-group). However, the ion-reorder-group isn't re-rendered to the correct order. The way I've worked around this for now, is by forcing a re-render by changing a different state variable.
trying to add the "add item" feature was a bit challenging but i finally got the code working the app-home.ts file was updated as follows
import { Component, Element, Prop, State, Listen } from '@stencil/core';
@Component({
tag: 'app-home',
styleUrl: 'app-home.css'
})
export class AppHome {
@Element() el: Element;
@Prop({ connect: 'ion-alert-controller' }) alertCtrl: HTMLIonAlertControllerElement;
@State() toggle: boolean = false;
list:Array<string>;
alert: HTMLIonAlertElement;
reorderGrpEL: HTMLIonReorderGroupElement;
validateIcon: HTMLIonIconElement;
addedValue: string;
hidInputs:Array<any>;
ionCardHeader: HTMLIonCardElement;
@Listen('ionItemReorder')
async itemReorderHandler(event: CustomEvent) {
let itemToMove:string = this.list.splice(event.detail.from,1)[0];
this.list.splice(event.detail.to,0,itemToMove);
console.log('in itemReorderHandlert this.list ',this.list);
}
@Listen('ionChange')
async inputChangeHandler($event: CustomEvent) {
this.addedValue = $event.detail.value;
if(this.addedValue.length > 1) {
this.validateIcon.classList.remove('not-visible');
} else {
this.validateIcon.classList.add('not-visible');
}
}
componentWillLoad() {
this.list = [
"deer",
"elephant",
"tiger",
"lion",
"eagle"
];
}
componentDidLoad() {
const ionCard: HTMLIonCardElement = this.el.querySelector("#reorder-card");
this.reorderGrpEL = ionCard.querySelector('#reorder_group');
this.ionCardHeader = this.el.querySelector('#header-card');
this.validateIcon = this.ionCardHeader.querySelector('.icon-validate');
}
async getNames(childs: NodeListOf<HTMLIonItemElement>): Promise<Array<string>> {
let retArray: Array<string> = [];
for(let i:number=0;i < childs.length;i++) {
retArray = [...retArray,childs[i].textContent];
if (i === childs.length -1 ) return Promise.resolve(retArray);
}
}
async presentAlert(options: any): Promise<void> {
this.alert = await this.alertCtrl.create(options);
await this.alert.present();
return;
}
async dismissAlert(): Promise<void> {
await this.alert.dismiss();
return;
}
async _deleteCancel() {
await this.dismissAlert();
}
async _deleteConfirm(item:string) {
let children:NodeListOf<HTMLIonItemElement> = this.reorderGrpEL.querySelectorAll('ion-item');
const arrayName:Array<string> = await this.getNames(children);
const index = arrayName.indexOf(item);
this.reorderGrpEL.removeChild(children[index]);
this.list.splice(index,1)
console.log('in deleteFromList this.list ',this.list);
await this.dismissAlert();
// this.toggle = !this.toggle;
}
async _handleItemClick(item:string) {
let options:any = {
header: 'Confirm Delete!',
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'alertcancel',
handler: () => {
this._deleteCancel();
}
}, {
text: 'Start',
cssClass: 'alertdanger',
handler:() => {
this._deleteConfirm(item);
}
}
]
}
await this.presentAlert(options);
}
_handleClick(button:string) {
switch (button) {
case 'button' : {
const div:HTMLDivElement = document.createElement('div');
div.setAttribute("id","div-add");
div.innerHTML = '<ion-textarea class="textarea-input" autofocus="true" rows="1" placeholder="Enter any value ..."></ion-textarea>';
const headerCard: HTMLIonCardElement = this.el.querySelector('#header-card');
headerCard.appendChild(div);
break;
}
case 'icon' : {
const value:string = this.addedValue;
const ionItem: HTMLIonItemElement = document.createElement('ion-item');
let innerHtml:string = '<ion-label>'+value +'</ion-label>';
innerHtml += '<ion-reorder slot="end"></ion-reorder>';
innerHtml += '<ion-icon id="ion-icon" name="trash" slot="end" color="danger"></ion-icon>';
ionItem.innerHTML = innerHtml;
this.reorderGrpEL.appendChild(ionItem);
const ionIcon:HTMLIonIconElement = ionItem.querySelector('#ion-icon');
ionIcon.onclick = () => {
this._handleItemClick(value)};
this.list = [...this.list,value];
console.log("in addToList this.list ",this.list);
break;
}
}
}
render() {
const reorderList = this.list.map((item) => {
return [
<ion-item>
<ion-label>{item}</ion-label>
<ion-reorder slot="end"></ion-reorder>
<ion-icon id="ion-icon" name="trash" slot="end" color="danger" onClick={() => this._handleItemClick(item)}></ion-icon>
</ion-item>
];
});
return [
<ion-header>
<ion-toolbar color="primary">
<ion-title>Home</ion-title>
</ion-toolbar>
</ion-header>,
<ion-content padding>
<ion-card id="header-card">
<ion-button class="button-button" ion-button icon-only color="light" onClick={ () => this._handleClick('button')}>
<ion-icon class="button-icon" name="add"></ion-icon>
</ion-button>
<ion-icon class="icon-validate not-visible" name="checkmark-circle-outline" slot="end" onClick={() => this._handleClick('icon')}></ion-icon>
</ion-card>
<ion-card id="reorder-card">
<ion-card-header class="reorder-card-header" color="light">Element List</ion-card-header>
<ion-list id="reorder-list" inset lines="inset">
<ion-reorder-group id="reorder_group" disabled={false}>
{reorderList}
</ion-reorder-group>
</ion-list>
</ion-card>
</ion-content>
];
}
}
and make it a bit nicer with a bit of css in the app-home.css
#header-card {
height:75px;
}
.reorder-card-header {
text-align:center;
font-size: 20px;
font-weight: bold;
}
#div-add {
position: relative;
z-index:999;
width: 160px;
left:90px;
top:-20px;
background-color:#f3f3f3;
border-style: solid;
border-width: 2px;
border-color:grey;
box-shadow : 0.5em 0.5em 0.75em -0.15em darkgrey;
}
.textarea-input{
--padding-top:5px;
--padding-bottom:5px;
}
.button-button {
position: relative;
top: 15px;
left: 10px;
}
.icon-validate {
position: relative;
width: 25px;
height: 25px;
top: 28px;
left:220px;
}
.not-visible {
visibility:hidden;
}
button.alert-button.alertdanger {
color: red !important;
}
So the question now: Is this the right way ? we directly write element dynamically in the DOM without going except the first time through the render function
if the answer is yes, we can close the issue
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.
Bug Report
Ionic Info Run
ionic info
from a terminal/cmd prompt and paste the output below.Ionic:
ionic (Ionic CLI) : 4.0.3
System:
NodeJS : v10.9.0 npm : 6.4.1 OS : macOS High Sierra
@stencil/core13.2 @ionic/core4.0.0-beta12 Describe the Bug when coupling the ionItemReorder and the delete item from a list element the display information is wrong
Related Code
Additional Context
the first display you get this![image](https://user-images.githubusercontent.com/16580653/46398092-6c886c80-c6f4-11e8-9bff-6be5fbfc7d66.png)
you move lion above tiger the display is correct as below![image](https://user-images.githubusercontent.com/16580653/46398196-bcffca00-c6f4-11e8-9960-79e9192302b5.png)
you now click on the trash icon of elephant to delete elephant from the list and the display is wrong see below![image](https://user-images.githubusercontent.com/16580653/46398335-254eab80-c6f5-11e8-8d96-3a82463d0a40.png)