Ionic-framework: [Feature Request] Programmatically slide an ion-item-sliding

Created on 26 Jul 2016  路  14Comments  路  Source: ionic-team/ionic-framework

Short description of the problem:

I would like to have a way to slide an item to open programmatically. It is not always intuitive to users the slide movement, but a button with an action that animates the slide could help to show how. To enable that, a public version of something like fireSwipeEventwould would help.

What behavior are you expecting?

I would like to have a method like slide() or open() that animate the ion-item-sliding to reveal the ion-item-options of that item.

Which Ionic Version? 2.x

Most helpful comment

For anyone looking to do this I found a way that is working quite well for me. It is behaving the same as the default drag method. Code is below. The HTML has extraneous markup but this has allowed me to put a more icon at the end of each item which is the click handler to programmatically open the item.

    <ion-item-sliding #slidingItem (tap)="slidingItem.close()">
        <ion-item>
          <ion-row>
            <ion-col col-auto>
              {{ item.date | date:'shortTime' }}
            </ion-col>
            <ion-col>
              {{ item.description }}
            </ion-col>
            <ion-col text-right>
              <button ion-button clear large (click)="openSlidingItem($event, slidingItem)">
                <ion-icon name="more"></ion-icon>
              </button>
            </ion-col>
          </ion-row>
        </ion-item>
        <ion-item-options>
          <button ion-button expandable type="button">
            Undo
          </button>
        </ion-item-options>
      </ion-item-sliding>
import { Component, ViewChildren, QueryList } from '@angular/core';
import { IonicPage, ItemSliding } from 'ionic-angular';

@IonicPage()
@Component({
  selector: 'page-my-page',
  templateUrl: 'my-page.html',
})
export class MyPage {
  @ViewChildren(ItemSliding) private slidingItems: QueryList<ItemSliding>;

  public openSlidingItem($event: Event, item: any) {
    // This is to prevent a call to itemSliding.close() in the template
    $event.stopPropagation();

    // Close all other open items to have behavior similar to the drag method
    this.closeAllItems();

    // In order for the width of the buttons to be calculated the item
    // must be slightly opened
    item._setOpenAmount(1);

    setTimeout(() => {
      const children = Array.from(
        // use _leftOptions if buttons are on the left (could be made to be dynamic)
        item._rightOptions._elementRef.nativeElement.children,
      );
      // Calculate the width of all of the buttons
      const width = children.reduce(
        (acc: number, child: HTMLElement) => acc + child.offsetWidth,
        0,
      );

      // Open to the calculated width
      item.moveSliding(width);
      item._setOpenAmount(width, false);
    }, 0);
  }

  private closeAllItems() {
    this.slidingItems.map(item => item.close());
  }
}

All 14 comments

Any update on this? I'm also trying to create a more intuitive interface by opening the item-option programatically. The fireSwipeEvent exists but is marked as private in item-sliding.d.ts.

Edit:
fireSwipeEvent would need a direction parameter since an item could exist with options on both sides.

Hello all! While this is an awesome feature request it is not something that we plan on doing anytime soon. Because of this I am going to move this to our internal feature tracking repo for now as it is just "collecting dust" here. Once we decide to implement this I will move it back. Thanks everyone for using Ionic!

This issue was moved to driftyco/ionic-feature-requests#50

@jgw96 your link is dead! Has the issue been moved or what is the status?

@jgw96 any update on this?

here is the implementation that I use
I hope it's clear, if not, just tell me to explain all that code :)

@ViewChildren('ionItemSliding') ionItemSlidings: any

 isSliding: any = [];

 openSlidingRemove(index, itemListEl){ let $this = this
     let itemSlide = this.ionItemSlidings.toArray()[index]
     if( itemSlide._openAmount == -0 ){
         setTimeout(()=>{
           itemSlide._setOpenAmount(60)
         },0)
     }

     this.isSliding[index] = true
     itemSlide._setOpenAmount(60)

     setTimeout(()=>{
       $this.isSliding[index] = false
     }, 200)
 }

 closeSlider(index){
    this.ionItemSlidings.toArray()[index].close()
  }

@iliasbhal

can you provide the markup??

import { Item, ItemSliding, ... } from 'ionic-angular';

//MORE CODE

openSlide(itemSlide: ItemSliding, item: Item) {
// Keep track of the last item slided so i can duplicate behaviour when another is being opened
    if(this.lastItemSliding){
      if(this.lastItemSliding.item['opened']){
        this.closeSlide(this.lastItemSliding);
      }
    }
    let eleRef =itemSlide.item.getElementRef();
//Get number of siblings buttons in ion-options to calculate the width to slide
    let options = eleRef.nativeElement['nextElementSibling']['children'].length;
    itemSlide.item['opened'] = true;
    itemSlide.setElementClass("active-sliding", true);
    itemSlide.setElementClass("active-slide", true);
    itemSlide.setElementClass("active-options-right", true);
    this.lastItemSliding = itemSlide;
// I used a FIXED width for ion-options buttons. Siblings Width can be used
    item.setElementStyle("transform", `translate3d(-${options*70}px, 0px, 0px)`);

  }
// I added a <button> in <ion-options> to close the slide, as the item doesn't trigger events when opened
  closeSlide(itemSlide: ItemSliding) {
    itemSlide.item['opened'] = false;
    itemSlide.close();
    setTimeout(()=>{
      itemSlide.setElementClass("active-slide", false);
      itemSlide.setElementClass("active-sliding", false);
      itemSlide.setElementClass("active-options-right", false);
    },600);
  }

A little late, but that is working for me as Ionic team hasn't responded.
hope it helpps.

This is a pretty common UX scenario. Often times users will not know what is a slide-able item and it helps to animate the process the first time the user interacts with the view.

1Password does this by having a context icon (three vertical dots). When you tap the dots the menu options slide out. Without this UX hint I would have no idea that the options are even there.

For anyone looking to do this I found a way that is working quite well for me. It is behaving the same as the default drag method. Code is below. The HTML has extraneous markup but this has allowed me to put a more icon at the end of each item which is the click handler to programmatically open the item.

    <ion-item-sliding #slidingItem (tap)="slidingItem.close()">
        <ion-item>
          <ion-row>
            <ion-col col-auto>
              {{ item.date | date:'shortTime' }}
            </ion-col>
            <ion-col>
              {{ item.description }}
            </ion-col>
            <ion-col text-right>
              <button ion-button clear large (click)="openSlidingItem($event, slidingItem)">
                <ion-icon name="more"></ion-icon>
              </button>
            </ion-col>
          </ion-row>
        </ion-item>
        <ion-item-options>
          <button ion-button expandable type="button">
            Undo
          </button>
        </ion-item-options>
      </ion-item-sliding>
import { Component, ViewChildren, QueryList } from '@angular/core';
import { IonicPage, ItemSliding } from 'ionic-angular';

@IonicPage()
@Component({
  selector: 'page-my-page',
  templateUrl: 'my-page.html',
})
export class MyPage {
  @ViewChildren(ItemSliding) private slidingItems: QueryList<ItemSliding>;

  public openSlidingItem($event: Event, item: any) {
    // This is to prevent a call to itemSliding.close() in the template
    $event.stopPropagation();

    // Close all other open items to have behavior similar to the drag method
    this.closeAllItems();

    // In order for the width of the buttons to be calculated the item
    // must be slightly opened
    item._setOpenAmount(1);

    setTimeout(() => {
      const children = Array.from(
        // use _leftOptions if buttons are on the left (could be made to be dynamic)
        item._rightOptions._elementRef.nativeElement.children,
      );
      // Calculate the width of all of the buttons
      const width = children.reduce(
        (acc: number, child: HTMLElement) => acc + child.offsetWidth,
        0,
      );

      // Open to the calculated width
      item.moveSliding(width);
      item._setOpenAmount(width, false);
    }, 0);
  }

  private closeAllItems() {
    this.slidingItems.map(item => item.close());
  }
}

@adamduren brilliant! Works a charm!

To make it work with left side buttons, not only did I need to change the item._rightOptions._elementRef.nativeElement.children line to item._leftOptions._elementRef.nativeElement.children, I also needed to change the _setOpenAmount value to negative, otherwise the slide still happened from the right.

item.moveSliding(width);
const numWidth = Number(width);
const negWidth = numWidth - (numWidth * 2);
item._setOpenAmount(negWidth, false);

This works - though I'm sure there's a better way.

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.

Was this page helpful?
0 / 5 - 0 ratings