import { Component, OnInit, AfterContentInit, ElementRef, TemplateRef, ContentChild, Output, EventEmitter, Input, Renderer2, ViewChild, AfterViewInit, HostBinding, SimpleChanges, OnChanges, ChangeDetectorRef, DoCheck } from '@angular/core'; import { ListViewHeaderTemplateDirective, ListViewTemplateDirective, ListViewFooterTemplateDirective, ListViewEmptyTemplateDirective, } from './template.directive'; import { PaginationInstance, PaginationControlsComponent } from '@farris/ui-pagination'; @Component({ selector: 'farris-list-view', templateUrl: './list-view.component.html', styleUrls: ['./list-view.component.scss'] }) export class ListViewComponent implements OnInit, OnChanges, AfterContentInit, AfterViewInit { @ContentChild(ListViewHeaderTemplateDirective, { read: TemplateRef }) headerTemplate: TemplateRef; @ContentChild(ListViewTemplateDirective, { read: TemplateRef }) listTemplate: TemplateRef; @ContentChild(ListViewFooterTemplateDirective, { read: TemplateRef }) footerTemplate: TemplateRef; @ContentChild(ListViewEmptyTemplateDirective, { read: TemplateRef }) emptyDataTemplate: TemplateRef; @ViewChild('listGroup') listGroup: ElementRef; @ViewChild('pager') pager: PaginationControlsComponent; // @Input() height:number; /** 列表数据 */ @Input() data = []; @Input() id: string; /** 数据为空是否展示默认 */ @Input() showEmpty = true; /** 是否自定义空数据模板 */ @Input() emptyTemplate = false; /** 是否支持多选 默认为false */ @Input() multipleSelect = false; /** 是否支持分页 默认false */ @Input() supportPaging = false; // 默认分页 @Input() pagerOnServer = true; @Input() pageSize = 10; @Input() pageIndex = 1; /** 启用跨页多选 */ @Input() enableMorePageSelect = false; @Input() showSelectedList = false; @Input() selectedItemFormat: (item: any) => string = null; /** * 保持选中状态,默认为 true; 启用多选后有效。 * 当设为false时,选中项再次点击将取消选中状态 */ @Input() keepSelect = true; // 是否平铺 @Input() fill = false; // 是否横向排列 @Input() cardLayout = false; _activeIndex: number; get activeIndex() { return this._activeIndex; } @Input() set activeIndex(val) { this._activeIndex = val; this.dataInit(); } @Input() listClassName: string; /** * 勾选值 */ @Input() checkValues: any[] = []; @Output() checkValuesChange: EventEmitter = new EventEmitter(); @Input() checkItems = []; @Input() checkItemsChange: EventEmitter<{items: any[], instance: any}> = new EventEmitter<{items: [], instance: any}>(); // @Input() borderBottom:boolean = true; private _pageList = [10, 20, 30, 50]; get pageList() { return this._pageList; } @Input() set pageList(val) { this._pageList = val; if (this.pager) { this.pager.setPageList(val); } } @Input() total = 0; /** 作为唯一标识的数据key值 如果没传 唯一标识为index值 */ @Input() listidName = 'id'; @HostBinding('class.f-listview-fill') get listviewFill() { return this.fill; } /** 点击某一行后 */ @Output() listClick = new EventEmitter(); /** 多选框 选中状态变化 */ @Output() checkChange = new EventEmitter(); // 分页事件 @Output() pageChanged = new EventEmitter(); @Output() pageSizeChanged = new EventEmitter(); /** 当前展示列表数据 */ currentData = []; /** 选中的列表数组 */ selectDataList = []; /** 跨页多选记录 */ selectDataListWithOtherPager = []; // 当前点击 public clickItem: any; public maxSize = 7; public directionLinks = true; public autoHide = false; public responsive = true; public paginationOptions: any = {}; public labels: any = { previousLabel: ' ', nextLabel: ' ', screenReaderPaginationLabel: 'Pagination', screenReaderPageLabel: 'page', screenReaderCurrentLabel: `You're on page` }; mouseInSelectedList = false; openSelectedList = false; constructor(private el: ElementRef, private renderer: Renderer2, private cdr: ChangeDetectorRef) { } ngOnInit() { this.paginationOptions = { id: 'Farris-listView-Pagination_' + (this.id || new Date().getTime()), itemsPerPage: this.pageSize, currentPage: this.pageIndex, pageList: this.pageList, totalItems: this.total, remote: this.pagerOnServer }; this.currentData = this.data; this.dataInit(); } ngOnChanges(changes: SimpleChanges) { if (changes.data && !changes.data.isFirstChange()) { this.currentData = this.data; this.dataInit(); } if (changes['total'] && this.total && this.paginationOptions) { this.paginationOptions['totalItems'] = this.total; this.paginationOptions = {...this.paginationOptions}; } if (changes['pageIndex'] && this.pageIndex && this.paginationOptions) { this.paginationOptions['currentPage'] = this.pageIndex; this.paginationOptions = {...this.paginationOptions}; } if (changes['pageSize'] && this.paginationOptions && !changes.pageSize.isFirstChange()) { this.paginationOptions['itemsPerPage'] = this.pageSize; this.paginationOptions = {...this.paginationOptions}; } if (changes && changes.checkValues !== undefined && !changes.checkValues.isFirstChange()) { const change = this.differenceBy(changes.checkValues.currentValue || [], changes.checkValues.previousValue || [], v => { return v; }); if (change) { if (!this.enableMorePageSelect) { this.checkRows(this.checkValues); } } } if (changes.checkItems && !changes.checkItems.isFirstChange()) { this.selectDataListWithOtherPager = [...this.checkItems]; const ids = this.checkItems.map(n => n[this.listidName]); this.checkedItems(ids, false); } } ngAfterViewInit() { } ngAfterContentInit() { } /** 默认搜索模板 点击搜索 */ searchList(searchField) { if (searchField !== '' && this.data && this.data.length) { this.currentData = this.data.filter((list) => { let result; const listValue = Object.values(list); for (let i = 0; i < listValue.length; i++) { if (typeof listValue[i] == 'string') { if (listValue[i].toString().includes(searchField)) { result = listValue[i].toString().includes(searchField); break; } } } return result; }); } else { this.currentData = this.data; } return { listdata: this.currentData, searchValue: searchField, length: this.currentData.length } } /** 点击某一列事件 */ listSelect(event, listItem, index, checkChangeEvent = false) { const isClickCheckbox = typeof event === 'boolean'; if (listItem['unClick'] || listItem['selectDisable']) { return; } else { this.checkChange.emit({ listdata: listItem, index }); if (this.multipleSelect) { if (listItem['checked']) { if (!this.keepSelect || isClickCheckbox) { // 支持多选 删除该选中行 const selectItemIndex = this.selectDataList.findIndex((item, i) => { return this.getKey(item, i) === this.getKey(listItem, index); }); this.selectDataList.splice(selectItemIndex, 1); this.updateDataListForMorePager('remove', listItem); listItem['checked'] = false; } } else { // 支持多选 插入该选中行 const result = this.selectDataList.find((value, i) => { return this.getKey(value, i) === this.getKey(listItem, index); }); if (!result) { this.selectDataList.unshift(listItem); this.updateDataListForMorePager('append', listItem); listItem['checked'] = true; } } // listItem['checked'] = !listItem['checked']; } else { // 不支持多选 替换当前选中行 this.selectDataList = []; this.selectDataList.push(listItem); } if (!checkChangeEvent) { this.clickItem = listItem; } this.listClick.emit({ data: this.selectDataList, index, checkChangeEvent }); } if (this.multipleSelect) { let ids = this.data.filter(item => !!item.checked).map(item => item[this.listidName]); if (this.enableMorePageSelect) { ids = this.selectDataListWithOtherPager.map(item => item[this.listidName]); } this.onCheckValuesChange(ids); } } /** 获得每一行list 唯一标识 */ getKey(list, index) { if (this.listidName && list.hasOwnProperty(this.listidName)) { return list[this.listidName]; } else { return index; } } /** checkbox状态变化 */ getSelect(event, changeData, i) { const state = event.checked; this.listSelect(state, changeData, i, true); } /** 排序事件 */ sort(sortkeyName, sortType = 'asc') { this.currentData.sort(this.compare(sortkeyName, sortType)); return { sortResult: { listdata: this.currentData, sortkeyName, sortType } }; } public selectRow(primaryValue: any) { if (this.currentData && this.currentData.length > 0) { const row = this.currentData.find(item => item[this.listidName] === primaryValue); if (row) { this.clickItem = row; this.cdr.markForCheck(); } } } private compare(KeyName, type) { if (type === 'desc') { return (obj1, obj2) => { const val1 = obj1[KeyName]; const val2 = obj2[KeyName]; if (val2 < val1) { return 1; } else if (val2 > val1) { return -1; } else { return 0; } }; } if (type === 'asc') { return (obj1, obj2) => { const val1 = obj1[KeyName]; const val2 = obj2[KeyName]; if (val2 > val1) { return 1; } else if (val2 < val1) { return -1; } else { return 0; } }; } } getItemActive(item) { // 不管是否开启多选,当前行只有一行 if (this.listidName && this.clickItem) { return item[this.listidName] === this.clickItem[this.listidName]; } else { return false; } } onPageChange(page: { pageIndex: number, pageSize: number }) { if (this.pageIndex !== page.pageIndex) { this.pageIndex = page.pageIndex; this.paginationOptions.currentPage = page.pageIndex; // this.paginationOptions = {...this.paginationOptions}; this.pageChanged.emit({ pageInfo: page }); } } onPageSizeChange(pageSize: number) { // console.log(this.pageSize !== pageSize && this.total); if (this.pageSize !== pageSize && this.total) { this.paginationOptions.itemsPerPage = pageSize; this.pageSize = pageSize; const total = this.total; let pageLength = Math.floor(total / pageSize); if (total % pageSize > 0) { pageLength += 1; } if (pageLength && this.pageIndex > pageLength) { this.pageIndex = pageLength; this.paginationOptions.currentPage = this.pageIndex; } // this.paginationOptions = {...this.paginationOptions}; this.pageSizeChanged.emit({ pageInfo: { pageIndex: this.pageIndex, pageSize } }); } } getCurrentData() { return this.currentData; } getSelectData() { return this.selectDataList; } /** 支持重新设置listview数据 */ setData(listviewData) { this.currentData = listviewData; this.data = listviewData; this.dataInit(); } dataInit() { if (this.data && this.data.length) { this.selectDataList = this.data.filter((list) => { return list['checked']; }); if (this.activeIndex >= 0 && this.activeIndex <= (this.data.length - 1)) { const dataItem = this.data[this.activeIndex]; if (dataItem) { this.clickItem = dataItem; this.selectDataList.push(this.clickItem); } } else if (this.activeIndex < 0) { return; } else { if (!this.selectDataList.length && !this.multipleSelect) { this.selectDataList.push(this.data[0]); } this.clickItem = this.data[0]; } } this.updateDataListForMorePager(); if (this.cdr) { this.cdr.detectChanges(); } } private updateDataListForMorePager(active: 'remove'|'append'|'' = '', listItem?: any, emit = true) { if (this.multipleSelect && this.enableMorePageSelect) { if (active === 'remove' && listItem) { if (!Array.isArray(listItem)) { this.selectDataListWithOtherPager = this.selectDataListWithOtherPager.filter(n => { if (typeof listItem === 'object') { return n[this.listidName] != listItem[this.listidName]; } else { return n[this.listidName] != listItem; } }); } else { this.selectDataListWithOtherPager = this.selectDataListWithOtherPager.filter(n => { return listItem.indexOf(a => a[this.listidName] === n[this.listidName]) === -1; }); } if (emit) { this.checkItemsChange.emit({items: [...this.selectDataListWithOtherPager], instance: this}); } } else if (active === 'append') { if (!Array.isArray(listItem)) { this.selectDataListWithOtherPager = [...this.selectDataListWithOtherPager, listItem]; } else { this.selectDataListWithOtherPager = [...this.selectDataListWithOtherPager, ...listItem]; } if (emit) { this.checkItemsChange.emit({items: [...this.selectDataListWithOtherPager], instance: this}); } } else { if (!this.selectDataListWithOtherPager.length) { this.selectDataListWithOtherPager = [...this.selectDataList]; } else { const newCheckeds = this.sameBy(this.currentData, this.selectDataListWithOtherPager, (v) => v[this.listidName]); if (newCheckeds && newCheckeds.length) { this.data.forEach(item => { item.checked = newCheckeds.includes(item[this.listidName]); }); } } } } } /** 全选 */ listCheckAll() { if (this.multipleSelect) { this.currentData.forEach(item => { item.checked = true; }); this.selectDataList = this.currentData.filter((list) => { return list['checked']; }); this.updateDataListForMorePager('append', this.currentData); this.cdr.markForCheck(); } } /** 取消全选 */ listCheckAllCancel() { if (this.multipleSelect) { this.currentData.forEach(item => { item.checked = false; }); this.selectDataList = []; this.updateDataListForMorePager('remove', this.currentData); this.cdr.markForCheck(); } } /** * 勾选行 * @param ids ids */ public checkRows(ids: any[]): void { if (this.multipleSelect) { if (!ids || ids.length < 1) { this.listCheckAllCancel(); return; } this.data.forEach(item => { if (ids.includes(item[this.listidName])) { item.checked = true; } else { item.checked = false; } }); // this.onCheckValuesChange(ids); this.cdr.markForCheck(); } } private onCheckValuesChange(ids: any[]) { this.checkValuesChange.emit(ids); } private differenceBy = (a, b, fn) => { const s = new Set(b.map(fn)); return a.map(fn).filter(el => !s.has(el)); } private sameBy = (a, b, fn) => { const s = new Set(b.map(fn)); return a.map(fn).filter(el => s.has(el)); } onMouseEnter($event) { $event.stopPropagation(); this.mouseInSelectedList = true; if (this.selectDataListWithOtherPager && this.selectDataListWithOtherPager.length) { this.openSelectedList = !this.openSelectedList; } else { this.openSelectedList = false; } } closeSelectedList() { this.openSelectedList = false; this.mouseInSelectedList = false; if (!this.cdr['destroyed']) { this.cdr.detectChanges(); } } onDelSelectedItem(id: any) { this.currentData.forEach(item => { if (item[this.listidName] == id) { item.checked = false; } }); this.selectDataList = this.selectDataList.filter(n => n[this.listidName] != id); this.updateDataListForMorePager('remove', id); this.updateCheckedValues(); } onClearSelected($event) { // this.clearSelectedItem.emit(); this.closeSelectedList(); this.listCheckAllCancel(); this.selectDataListWithOtherPager = []; this.checkValues = []; this.onCheckValuesChange([]); } onSelectListPanelClose($event) { this.closeSelectedList(); } private updateCheckedValues(emit = true) { if (this.multipleSelect) { if (!this.enableMorePageSelect) { this.checkValues = this.selectDataList.map(n => n[this.listidName]); } else { this.checkValues = this.selectDataListWithOtherPager.map(n => n[this.listidName]); } if (emit) { this.onCheckValuesChange(this.checkValues); this.checkItemsChange.emit({ items: this.selectDataListWithOtherPager, instance: this }); } } } clearCheckeds(clearAll = true, emit = true) { if (this.multipleSelect) { this.currentData.forEach(item => { item.checked = false; }); this.selectDataList = []; if (clearAll) { this.selectDataListWithOtherPager = []; } else { this.updateDataListForMorePager('remove', this.currentData); } if (emit) { this.updateCheckedValues(emit); } this.cdr.markForCheck(); } } private _setItemsCheckedStatus( ids: any, checked: boolean, emit: boolean) { if (ids && ids.length) { const action = checked ? 'append': 'remove'; ids.forEach(i => { let id = i; if (typeof i === 'object') { id = i[this.listidName]; } const item = this.data.find(n => n[this.listidName] === id); if (item) { item.checked = checked; } if (checked) { this.updateDataListForMorePager('append', i, false); } else { this.updateDataListForMorePager('remove', id, false); } }); this.updateCheckedValues(emit); this.cdr.markForCheck(); } } unCheckItems(ids: number[] | string[] | object[], emit = false) { this._setItemsCheckedStatus(ids, false, emit); } checkedItems(ids: object[], emit = false) { this._setItemsCheckedStatus(ids, true, emit); } }