项目作者: Guley

项目描述 :
Swipe To Delete Angular 6 With HammerJs
高级语言: TypeScript
项目地址: git://github.com/Guley/swipetodel.git
创建时间: 2019-09-17T10:17:14Z
项目社区:https://github.com/Guley/swipetodel

开源协议:GNU General Public License v3.0

下载


Welcome to Swipe To Delete

This project was generated with Angular CLI version 1.6.5.

Development server

Run ng serve for a dev server. Navigate to http://localhost:4200/. The app will automatically reload if you change any of the source files.

Packages :

npm i hammerjs

npm i @angular/material

Config Folder

create a new folder named as config and make 2 new files inside it configuration.ts and GestureConfig.ts

configuration.ts

  1. export interface Configuration {
  2. slideThreshold ?: number;
  3. listType ?: string;
  4. classname ?: string;
  5. disableWarnings?: boolean;
  6. numberOfDeleteIcon?: number
  7. }

GestureConfig.ts

  1. import { HammerGestureConfig, } from '@angular/platform-browser';
  2. export class GestureConfig extends HammerGestureConfig {
  3. overrides = {
  4. pan: {
  5. touchAction: 'auto',
  6. direction: 6
  7. },
  8. pinch: {
  9. enable: false
  10. },
  11. rotate: {
  12. enable: false
  13. },
  14. swipe: {
  15. enable: false
  16. }
  17. };
  18. }

constants Folder

create a new folder named as constants and make 3 new files inside it constants.ts , list-type.ts and warnings.ts

constants.ts

  1. export const Constants = {
  2. CONFIG_NOT_LOADED : `You have not provided the configuration values, default will be loaded.`,
  3. ADDING_DEFAULT_SLIDE_THRESHOLD: `Will keep it default i.e.`,
  4. SLIDE_THRESHOLD_NOT_FOUND: `You have not provided the slideThreshold.`,
  5. ZERO_SLIDE_THRESHOLD_NOT_ALLOWED: `slideThreshold value can not be 0 or less than 0.`,
  6. MAX_SLIDE_THRESHOLD_NOT_ALLOWED: `slideThreshold value should be less than 50.`,
  7. INVALID_SLIDE_THRESHOLD_NOT_ALLOWED: `slideThreshold value is invalid, Expecting number between 0 to 50.`,
  8. MAX_SLIDE_THRESHOLD: 50,
  9. MIN_SLIDE_THRESHOLD: 0,
  10. DEFAULT_SLIDE_THRESHOLD: 12,
  11. NUMBER_OF_DELETE_ICONS : 2,
  12. DEFAULT_CLASS_NAME: `ngstd-main-canvas`
  13. };

list-type.ts

  1. export enum ListType {
  2. SINGLELINE = 'singleline',
  3. MULTILINE = 'multiline',
  4. LISTWITHICON = 'listwithicon',
  5. LISTWITHIMAGE = 'listwithimage',
  6. }

warnings.ts

  1. export enum Warnings {
  2. CONFIG_NOT_LOADED = 'CONFIG_NOT_LOADED',
  3. ADDING_DEFAULT_SLIDE_THRESHOLD = 'ADDING_DEFAULT_SLIDE_THRESHOLD',
  4. ZERO_SLIDE_THRESHOLD_NOT_ALLOWED = 'ZERO_SLIDE_THRESHOLD_NOT_ALLOWED',
  5. SLIDE_THRESHOLD_NOT_FOUND = 'SLIDE_THRESHOLD_NOT_FOUND',
  6. MAX_SLIDE_THRESHOLD_NOT_ALLOWED = 'MAX_SLIDE_THRESHOLD_NOT_ALLOWED',
  7. INVALID_SLIDE_THRESHOLD_NOT_ALLOWED = 'INVALID_SLIDE_THRESHOLD_NOT_ALLOWED'
  8. }

MaterialsModule.ts

  1. import { NgModule } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import {
  4. MatIconModule,
  5. MatListModule,
  6. MatRippleModule,
  7. } from '@angular/material';
  8. @NgModule({
  9. imports: [
  10. MatIconModule,
  11. MatListModule,
  12. MatRippleModule,
  13. ],
  14. declarations: [],
  15. exports: [
  16. MatIconModule,
  17. MatListModule,
  18. MatRippleModule,
  19. ]
  20. })
  21. export class MaterialsModule { }

app.module.ts

  1. import { NgModule } from '@angular/core';
  2. import { BrowserModule } from '@angular/platform-browser';
  3. import { FormsModule } from '@angular/forms';
  4. import { CommonModule } from '@angular/common';
  5. import { HAMMER_GESTURE_CONFIG } from '@angular/platform-browser';
  6. import { MaterialsModule } from './MaterialsModule';
  7. import { GestureConfig } from './config/GestureConfig';
  8. import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
  9. import 'hammerjs/hammer';
  10. import { AppComponent } from './app.component';
  11. @NgModule({
  12. imports: [ BrowserModule, FormsModule, MaterialsModule, BrowserAnimationsModule ],
  13. declarations: [ AppComponent ],
  14. bootstrap: [ AppComponent ],
  15. providers: [{
  16. provide: HAMMER_GESTURE_CONFIG,
  17. useClass: GestureConfig,
  18. }]
  19. })
  20. export class AppModule { }

app.component.ts

  1. import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
  2. import { trigger, style, keyframes, transition, animate, query, stagger } from '@angular/animations';
  3. import { Configuration } from './config/configuration';
  4. import { ListType } from './constants/list-type';
  5. import { Warnings } from './constants/warnings';
  6. import { Constants } from './constants/constants';
  7. @Component({
  8. selector: 'my-app',
  9. templateUrl: './app.component.html',
  10. styleUrls: [ './app.component.css' ],
  11. animations: [
  12. trigger('listAnimation', [
  13. transition('* => *', [
  14. query(':leave', [
  15. stagger(100, [
  16. animate('0s', style({ opacity: '0' })),
  17. animate('0.2s', style({ height: '0px', opacity: '0', display: 'none' }))
  18. ])
  19. ], { optional: true })
  20. ])
  21. ]),
  22. trigger('slideLeft', [
  23. transition('* => *', animate(100, keyframes([
  24. style({ left: '*', offset: 0 }),
  25. style({ left: '0', offset: 1 }),
  26. ])
  27. ))
  28. ])
  29. ]
  30. })
  31. export class AppComponent {
  32. @Input() items: any;
  33. @Input() configuration: Configuration = null;
  34. @Output() deletedItem = new EventEmitter<any>();
  35. ngstdIndexNumber:number = null;
  36. disableWarnings = false;
  37. listType: string = null;
  38. slideThreshold: number;
  39. numberOfDeleteIcon: number = null;
  40. classname: string = null;
  41. isInvalidConfig: boolean = null;
  42. elementLeftSign = true;
  43. deletedResult = null;
  44. constructor() { }
  45. ngOnInit() {
  46. this.initializeSWipeList();
  47. this.items = [
  48. {
  49. title: 'Iron Man',
  50. icon: `pan_tool`,
  51. img: `https://image.flaticon.com/icons/png/512/663/663084.png`,
  52. description: `Iron Man is a fictional superhero. A wealthy American business magnate, playboy, and ingenious scientist, Anthony Edward "Tony" Stark suffers a severe chest injury during a kidnapping. `,
  53. data: {
  54. name: 'Tony Stark',
  55. abilities: [
  56. 'Flying', 'Shooting', 'billionaire'
  57. ]
  58. }
  59. },
  60. {
  61. title: 'Capton America',
  62. icon: `view_stream`,
  63. img: `https://image.flaticon.com/icons/png/512/663/663077.png`,
  64. description: `Captain America is a fictional superhero.Captain America is the alter ego of Steve Rogers, a frail young man enhanced to the peak of human perfection by an experimental serum to aid the United States government's efforts in World War II.`,
  65. data: {
  66. name: 'Steve Rogers',
  67. abilities: [
  68. 'Strong', 'Very Strong'
  69. ]
  70. }
  71. },
  72. {
  73. title: 'Dr Strange',
  74. icon: `offline_bolt`,
  75. img: `https://image.flaticon.com/icons/png/512/663/663089.png`,
  76. description: `Doctor Stephen Vincent Strange is a fictional superhero. After a car accident severely damages his hands and hinders his ability to perform surgery, he searches the globe for a way to repair them and encounters the Ancient One. `,
  77. data: {
  78. name: 'Steven Strange',
  79. abilities: [
  80. 'Master of Mystic Art'
  81. ]
  82. }
  83. },
  84. {
  85. title: 'Shaktiman',
  86. icon: `flash_on`,
  87. img: `https://image.flaticon.com/icons/png/512/663/663086.png`,
  88. description: `Shaktimaan is an Indian fictional superhero. Shaktimaan is depicted as a human who has attained superhuman strength and power through deep meditation and attaining control over five elements of life.`,
  89. data: {
  90. name: 'Pandit Gangadhar',
  91. abilities: [
  92. 'Attractive male', 'Healing', 'Will power-based constructs', 'Flying'
  93. ]
  94. }
  95. },
  96. {
  97. title: 'The Winter Soldier',
  98. icon: `trending_up`,
  99. img: `https://image.flaticon.com/icons/png/512/663/663088.png`,
  100. description: `James Buchanan "Bucky" Barnes is a fictional superhero. James Buchanan Barnes was born in Shelbyville, Indiana in 1925. Barnes grew up as an Army brat. `,
  101. data: {
  102. name: 'James Buchanan "Bucky" Barnes',
  103. abilities: [
  104. 'Hand to hand combat and Martial arts', 'Strong Arm'
  105. ]
  106. }
  107. },
  108. {
  109. title: 'The Batman',
  110. icon: `attach_money`,
  111. img: `https://image.flaticon.com/icons/png/512/663/663076.png`,
  112. description: ` Batman does not possess any superpowers; rather, he relies on his genius intellect, physical prowess, martial arts abilities, detective skills, science and technology, vast wealth, intimidation, and indomitable will. A large assortment of villains make up Batman's rogues gallery, including his archenemy, the Joker.`,
  113. data: {
  114. name: 'Bruce wayne',
  115. abilities: [
  116. 'Rich', 'Strong'
  117. ]
  118. }
  119. },
  120. {
  121. title: 'The Superman',
  122. icon: `send`,
  123. img: `https://image.flaticon.com/icons/png/512/663/663079.png`,
  124. description: `Early in his childhood, he displays various superhuman abilities, which, upon reaching maturity, he resolves to use for the benefit of humanity through a "Superman" identity.`,
  125. data: {
  126. name: 'Clark Kent',
  127. abilities: [
  128. 'Attractive male', 'Healing', 'Will power-based constructs', 'Flying'
  129. ]
  130. }
  131. },
  132. {
  133. title: 'The Black Panther',
  134. icon: `send`,
  135. img: `https://image.flaticon.com/icons/png/512/663/663078.png`,
  136. description: `Black Panther's real name is T'Challa, king and protector of the fictional African nation of Wakanda.`,
  137. data: {
  138. name: `King T'Challa`,
  139. abilities: [
  140. 'Superhumanly acute senses', 'Enhanced strength', 'Speed', 'Agility', 'Stamina', 'Durability', 'Healing', 'Reflexes'
  141. ]
  142. }
  143. },
  144. {
  145. title: 'The Hulk',
  146. icon: `send`,
  147. img: `https://image.flaticon.com/icons/png/512/663/663083.png`,
  148. description: `Hulk, a green-skinned, hulking and muscular humanoid possessing a vast degree of physical strength, and his alter ego Bruce Banner.`,
  149. data: {
  150. name: `Bruce Banner`,
  151. abilities: [
  152. 'Limitless physical strength'
  153. ]
  154. }
  155. }
  156. ]
  157. }
  158. initializeSWipeList(): void {
  159. this.detectInvalidConfig();
  160. this.setDisableWarnings();
  161. this.setslideThreshold();
  162. this.setNumberOfDeleteIcon();
  163. this.setlistType();
  164. }
  165. detectInvalidConfig(): void {
  166. if (this.configuration === null || this.configuration === undefined || this.configuration === '') {
  167. this.isInvalidConfig = true;
  168. this.logWarnings(Warnings.CONFIG_NOT_LOADED);
  169. } else {
  170. this.isInvalidConfig = false;
  171. }
  172. }
  173. setNumberOfDeleteIcon(): void {
  174. const config = this.configuration;
  175. if (this.isInvalidConfig || config.numberOfDeleteIcon === 2) {
  176. this.numberOfDeleteIcon = Constants.NUMBER_OF_DELETE_ICONS;
  177. } else{
  178. this.numberOfDeleteIcon = null;
  179. }
  180. }
  181. setslideThreshold(): void {
  182. if (this.isInvalidConfig) {
  183. this.slideThreshold = Constants.DEFAULT_SLIDE_THRESHOLD;
  184. this.logWarnings(Warnings.SLIDE_THRESHOLD_NOT_FOUND, `${Constants.ADDING_DEFAULT_SLIDE_THRESHOLD} ${Constants.DEFAULT_SLIDE_THRESHOLD}%.`);
  185. return;
  186. }
  187. const config = this.configuration;
  188. if (config.slideThreshold === null || config.slideThreshold === undefined || typeof config.slideThreshold !== 'number') {
  189. if (typeof config.slideThreshold !== 'number') {
  190. this.logWarnings(Warnings.INVALID_SLIDE_THRESHOLD_NOT_ALLOWED, `${Constants.ADDING_DEFAULT_SLIDE_THRESHOLD} ${Constants.DEFAULT_SLIDE_THRESHOLD}%.`);
  191. } else {
  192. this.logWarnings(Warnings.SLIDE_THRESHOLD_NOT_FOUND, `${Constants.ADDING_DEFAULT_SLIDE_THRESHOLD} ${Constants.DEFAULT_SLIDE_THRESHOLD}%.`);
  193. }
  194. this.slideThreshold = Constants.DEFAULT_SLIDE_THRESHOLD;
  195. } else {
  196. if (config.slideThreshold < Constants.MIN_SLIDE_THRESHOLD || config.slideThreshold === Constants.MIN_SLIDE_THRESHOLD || config.slideThreshold > Constants.MAX_SLIDE_THRESHOLD) {
  197. if (config.slideThreshold > Constants.MAX_SLIDE_THRESHOLD) {
  198. this.logWarnings(Warnings.MAX_SLIDE_THRESHOLD_NOT_ALLOWED, `${Constants.ADDING_DEFAULT_SLIDE_THRESHOLD} ${Constants.DEFAULT_SLIDE_THRESHOLD}%.`);
  199. }
  200. if (config.slideThreshold < Constants.MIN_SLIDE_THRESHOLD || config.slideThreshold === Constants.MIN_SLIDE_THRESHOLD) {
  201. this.logWarnings(Warnings.ZERO_SLIDE_THRESHOLD_NOT_ALLOWED, `${Constants.ADDING_DEFAULT_SLIDE_THRESHOLD} ${Constants.DEFAULT_SLIDE_THRESHOLD}%.`);
  202. }
  203. this.slideThreshold = Constants.DEFAULT_SLIDE_THRESHOLD;
  204. } else {
  205. this.slideThreshold = config.slideThreshold;
  206. }
  207. }
  208. }
  209. setlistType(): void {
  210. const config = this.configuration;
  211. if (this.isInvalidConfig || config.listType === `` || config.listType === undefined || config.listType === null) {
  212. this.listType = ListType.LISTWITHIMAGE;
  213. } else {
  214. const listType = config.listType.trim();
  215. switch (listType) {
  216. case ListType.SINGLELINE:
  217. case ListType.MULTILINE:
  218. case ListType.LISTWITHICON:
  219. case ListType.LISTWITHIMAGE:
  220. this.listType = listType;
  221. break;
  222. default:
  223. this.listType = ListType.SINGLELINE;
  224. }
  225. }
  226. }
  227. setDisableWarnings(): void {
  228. if (this.isInvalidConfig) {
  229. this.disableWarnings = false;
  230. } else {
  231. const config = this.configuration;
  232. this.disableWarnings = (config.disableWarnings && config.disableWarnings !== undefined && config.disableWarnings !== null) ? true : false;
  233. }
  234. }
  235. getClassName(): string{
  236. if (this.isInvalidConfig) {
  237. return `${Constants.DEFAULT_CLASS_NAME}`;
  238. } else {
  239. if (this.configuration.classname !== '' && this.configuration.classname !== null && this.configuration.classname !== undefined ){
  240. return `${Constants.DEFAULT_CLASS_NAME} ${this.configuration.classname}`;
  241. } else {
  242. return `${Constants.DEFAULT_CLASS_NAME}`;
  243. }
  244. }
  245. }
  246. panend(action, index, elementRefrence): void {
  247. const currentMargin = this.getLeftPosition(elementRefrence);
  248. if (currentMargin > this.slideThreshold ||
  249. (currentMargin < - this.slideThreshold && this.numberOfDeleteIcon === Constants.NUMBER_OF_DELETE_ICONS)) {
  250. this.removeElement(index);
  251. } else {
  252. this.ngstdIndexNumber = index;
  253. }
  254. }
  255. panmove(action, elementRefrence): void {
  256. elementRefrence.style.left = action.deltaX + 'px';
  257. elementRefrence.offsetLeft > 0 ? this.elementLeftSign = true : this.elementLeftSign = false;
  258. }
  259. alignComplete(event): void {
  260. event.element.style.left = '0px';
  261. event.element.offsetLeft > 0 ? this.elementLeftSign = true : this.elementLeftSign = false;
  262. this.ngstdIndexNumber = null;
  263. }
  264. getLeftSign() {
  265. return this.elementLeftSign ? true : false;
  266. }
  267. removeElement(index): void {
  268. const deletedItem = this.items[index];
  269. this.deletedResult = deletedItem;
  270. this.items.splice(index, 1);
  271. this.deletedItem.emit(deletedItem);
  272. }
  273. getLeftPosition(elementRefrence): number {
  274. const currentleftPosition = elementRefrence.style.left.slice(0, -2);
  275. if (currentleftPosition !== null) {
  276. return (parseInt(
  277. currentleftPosition, 10
  278. ) * 100) / window.innerWidth;
  279. } else {
  280. return 0;
  281. }
  282. }
  283. logWarnings(warningFor: string, extraMessage: any = null): void {
  284. if (this.disableWarnings) {
  285. return;
  286. }
  287. switch (warningFor) {
  288. case Warnings.CONFIG_NOT_LOADED:
  289. case Warnings.SLIDE_THRESHOLD_NOT_FOUND:
  290. case Warnings.ZERO_SLIDE_THRESHOLD_NOT_ALLOWED:
  291. case Warnings.MAX_SLIDE_THRESHOLD_NOT_ALLOWED:
  292. case Warnings.INVALID_SLIDE_THRESHOLD_NOT_ALLOWED:
  293. extraMessage === null ? console.warn(this.getConstValue(warningFor)) : console.warn(this.getConstValue(warningFor), extraMessage);
  294. break;
  295. default:
  296. // unicons !
  297. }
  298. }
  299. getConstValue(constantName: string): string {
  300. return Constants[constantName];
  301. }
  302. }

app.component.html

  1. <div *ngIf="deletedResult">
  2. You Deleted :
  3. {{ deletedResult | json}}
  4. </div>
  5. <div [ngClass]="getClassName()">
  6. <mat-list [@listAnimation]="items.length">
  7. <mat-list-item class="ngstd-list-item" *ngFor="let item of items;let i = index">
  8. <div class="ngstd-delete-indicator">
  9. <i class="material-icons ngstd-delete-icon" *ngIf="getLeftSign()">delete_sweep</i>
  10. <span> </span>
  11. <i class="material-icons ngstd-delete-icon" *ngIf="numberOfDeleteIcon === 2 && !getLeftSign()">delete_sweep</i>
  12. </div>
  13. <div #elementRefrence class="ngstd-item-container "
  14. (panend)="panend($event, i, elementRefrence)"
  15. (panmove)="panmove($event,elementRefrence)"
  16. [@slideLeft]="ngstdIndexNumber === i"
  17. (@slideLeft.done)=alignComplete($event)
  18. >
  19. <ng-container *ngIf="listType === 'listwithimage'">
  20. <img matListAvatar src="{{item.img}}" alt="{{item.title}}">
  21. <div class="mat-list-text ngstd-details">
  22. <h3 matLine> {{item.title}}</h3>
  23. <p matLine>
  24. <span> {{item.description}} </span>
  25. </p>
  26. </div>
  27. </ng-container>
  28. <ng-container *ngIf="listType === 'listwithicon'">
  29. <mat-icon class="ngstd-icon" mat-list-icon>{{item.icon}}</mat-icon>
  30. <div class="mat-list-text ngstd-details">
  31. <h4 mat-line>{{item.title}}</h4>
  32. <p mat-line> {{item.description}} </p>
  33. </div>
  34. </ng-container>
  35. <ng-container *ngIf="listType === 'singleline'">
  36. <mat-list-item> {{item.title}} </mat-list-item>
  37. </ng-container>
  38. <ng-container *ngIf="listType === 'multiline'">
  39. <div class="mat-list-text ngstd-details">
  40. <h3 matLine> {{item.title}} </h3>
  41. <p matLine>
  42. <span> {{item.description}} </span>
  43. <span class="demo-2"> -- {{item.description}} </span>
  44. </p>
  45. </div>
  46. </ng-container>
  47. </div>
  48. <mat-divider></mat-divider>
  49. </mat-list-item>
  50. </mat-list>
  51. </div>

app.component.css

  1. .ngstd-main-canvas /deep/
  2. mat-list-item .mat-list-item-content {
  3. padding: 0 !important;
  4. }
  5. .ngstd-main-canvas .ngstd-delete-indicator {
  6. height: 97%;
  7. width: 98%;
  8. background-color: rebeccapurple;
  9. display: flex;
  10. justify-content: space-between;
  11. position: absolute;
  12. align-items: center;
  13. flex-shrink: 0;
  14. margin-left: 0.5%;
  15. }
  16. .ngstd-main-canvas .ngstd-delete-indicator .ngstd-delete-icon {
  17. margin-left: 16px;
  18. margin-right: 16px;
  19. width: 24px;
  20. height: 24px;
  21. font-size: 24px;
  22. color: #fff;
  23. }
  24. .ngstd-main-canvas .ngstd-item-container {
  25. padding: 0 16px !important;
  26. background-color: #fff;
  27. width: 100%;
  28. display: flex;
  29. flex-direction: row;
  30. align-items: center;
  31. box-sizing: border-box;
  32. padding: 0 16px;
  33. position: relative;
  34. height: inherit;
  35. }
  36. .ngstd-main-canvas .ngstd-item-container .ngstd-details {
  37. padding-left: 16px !important;
  38. }
  39. .ngstd-main-canvas .ngstd-item-container .ngstd-icon {
  40. color: rgba(0, 0, 0, 0.54);
  41. }

This project is inspired from (https://github.com/ShankyTiwari/Swipe-To-Delete-in-Angular-using-animations)