Angular 2 передает событие щелчка повторно используемому универсальному компоненту

У меня есть несколько компонентов, которые используют в основном одну и ту же таблицу, поэтому я нахожусь в процессе абстрагирования этой таблицы. Я решил большую часть своих потребностей в заполнении динамических таблиц, но еще не нашел решения для следующего.

В одном из моих экземпляров таблицы строки должны быть интерактивными. В исходной таблице я просто добавил событие щелчка в строку и вызвал функцию в моем машинописном файле.

Теперь, когда таблица является дочерним элементом любого потребляющего компонента, я не знаю, как динамически добавить это событие щелчка. Вот, по сути, то, чего я пытаюсь достичь:

HTML:
<tr class="someClass" <!-- want click event here -->>
  <td *ngFor="let column of row;"><div [innerHtml]="column"></div></td>
</tr>

Это файл машинописи таблиц, где все данные поступают в объект visibleData:

export class GenericTableComponent implements OnInit {
    @Input() visibleData;
    constructor() { }

    ngOnInit() {
    }
}

Я реализую общую таблицу в своем родительском HTML здесь

Parent HTML:
<oma-generic-table [visibleData]="visibleData"></oma-generic-table>

А вот функция в родительском элементе, которая подготавливает данные. Я попытался сохранить событие щелчка в строке и передать его, но все, что я пробовал до сих пор, не удалось (привязка данных с помощью {{}}, квадратные скобки и т. д.).

transformData(visibleData) {
    const ret: any = {};
    ret.headings = visibleData.headings;
    ret.action = '(click)="rowClicked([row.id])"';
    ret.checkbox = this.checkBox;                                                   //add if the table needs checkboxes
    ret.content = [];
    for (let i = 0; i < visibleData.content.length; i++) {
        ret.content.push(_.values(_.omit(visibleData.content[i], 'id')));
    }
    return ret;
}

Однако даже при жестком кодировании в дочернем элементе событие click не распознает функцию в родительском элементе, и я получаю следующую ошибку:

EXCEPTION: Error in ./GenericTableComponent class GenericTableComponent - inline template:35:4 caused by: self.parentView.context.rowClicked is not a function
ORIGINAL EXCEPTION: self.parentView.context.rowClicked is not a function

Я не уверен, что это что-то простое или нет. Я новичок в Angular 2, поэтому прошу прощения, если этот вопрос упрощен. Заранее благодарю за любую помощь.


person Chris Sharp    schedule 22.02.2017    source источник


Ответы (3)


Ваша общая таблица может генерировать пользовательские события, на которые может подписаться родительский компонент:

@Component({
    selector: 'oma-generic-table',
    template: `
        <table>
            <tr *ngFor="let row of visibleData" class="someClass" (click)="selectRow(row)">
              <td *ngFor="let column of row;"><div [innerHtml]="column"></div></td>
            </tr>
        </table>
    `
})
export class OmaGenericTable {

    @Input() visibleData: VisibleDataRow[];

    @Output() select = new EventEmitter<VisibleDataRow>();

    selectRow(row: VisibleDataRow) {
        this.select.emit(row);
    }
}

Затем в вашем родительском компоненте:

// in template
<oma-generic-table 
        [visibleData]="visibleData" 
        (select)="tableRowSelected($event)"
></oma-generic-table>

// in component
tableRowSelected(r: VisibleDataRow) {
    console.log(`Selected row ${r}`);
}
person Vilmantas Baranauskas    schedule 22.02.2017
comment
Спасибо за это элегантное решение. У меня есть пара вопросов. 1. Где объявлено «VisibleDataRow»? Передаваемый объект представляет собой сложный объект, который включает в себя заголовки таблиц и массивы строк с некоторыми другими свойствами. Я не уверен, что представляет собой VisibleDataRow, или мое первоначальное объяснение было недостаточным. Извиняюсь, если ввел в заблуждение. 2. Чтобы сделать интерактивную функцию необязательной, я рассматривал возможность передачи строки 'style=cursor: pointer' любым родителям, которые хотят сделать строки интерактивными. Это хакерский подход? Спасибо еще раз! - person Chris Sharp; 22.02.2017
comment
1. Поскольку вы не указали какой-либо тип строк в своем вопросе, я просто использовал VisibleDataRow для его представления. visibleData — это массив любых объектов, которые у вас могут быть. 2. Вы можете добавить еще один входной параметр [selectable]=true, чтобы включить/выключить выбор строки таблицы. Внутри вашего OmaGenericTableComponent вы можете связать необходимый класс css на основе этого входного параметра, используя @HostBinding('class.selectable') @Input() selectable: boolean; декларация. - person Vilmantas Baranauskas; 23.02.2017

Насколько мне известно, Angular2 не будет привязываться к событию «(щелчок)» таким образом. Это может выглядеть некрасиво, но я бы добавил директиву NgIf в таблицу в строке, на которую должно воздействовать событие щелчка, и в обратном порядке применил логику к другой строке, на которую не должно влиять событие щелчка. Бывший:

<tr *ngIf="!isClickable" class="someClass"> <tr *ngIf="isClickable" class="someClass" (click)="rowClicked()> <td *ngFor="let column of row;"><div [innerHtml]="column"></div></td> </tr>

Затем вы можете передать переменную isClickable в качестве входных данных в свою таблицу из любого места, где вы создаете экземпляр компонента таблицы, и воздействовать на него.

person Devon Germano    schedule 22.02.2017

Использование этого в HTML

<tr *ngIf="!isClickable" class="someClass">
 <tr *ngIf="isClickable" class="someClass" #click>
  <td *ngFor="let column of row;"><div [innerHtml]="column"></div></td>
 </tr>

это в машинописи

export class GenericTableComponent implements OnInit {
    @Input() visibleData;
    @ViewChild('click') protected _click:ElementRef;

    constructor(enderer: Renderer) {
        renderer.listen(this._click.nativeElement, 'click', (event) => {
            // Do something with 'event'
        })
    }
}

Надеюсь, это поможет вам

person Youngz ie    schedule 22.02.2017