I have a Angular material table, each table row expands when it's click
within the last cell I load a component dynamically with ComponentFactory the loaded component is a dropdown.
The issue I'm having is when the dropdown is clicked the table row will expand and contract.
This is how I add function to the rows
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;let index=index" (click)="expandRow(index, row)" #myRow></mat-row>
This is the cell, where user side menu is loaded in:
<ng-container *ngIf="column === 'viewSelection'">
<ng-container matColumnDef="viewSelection">
<mat-header-cell *matHeaderCellDef></mat-header-cell>
<mat-cell *matCellDef="let row">
<ng-container #sideMenu></ng-container>
<!-- <user-side-menu></user-side-menu> -->
</mat-cell>
</ng-container>
</ng-container>
How the user menu is loaded, which works fine:
let sideMenu = this.sideMenu.toArray()
for (let i = 0; i < sideMenu.length; i++) {
const factory = this.resolver.resolveComponentFactory(this.ellipsis);
let container = this.sideMenu.toArray()[i]
const ellipsisComponent = container.createComponent(factory);
ellipsisComponent.instance.data = this.returnedData[i]
console.log(container, ellipsisComponent.data);
Html for loaded user menu:
<a aria-expanded="false" aria-haspopup="true" class="btn btn-icon has-dropdown" data-toggle="dropdown" id="grid-menu">
<i class="ion-more"></i>
</a>
<div class="c-dropdown__menu dropdown-menu" aria-labelledby="grid-menu">
<a class="c-dropdown__item dropdown-item" (click)="viewUser({Id:data?.Id}, $event); $event.preventDefault()" >View/Edit User</a>
<a *ngIf="data?.IsActive" class="c-dropdown__item dropdown-item" (click)="activeDeactivateUser(data?.Id, false); $event.preventDefault()" data-toggle="modal" data-target="#deactivate-member">Deactivate User</a>
<a *ngIf="!data?.IsActive" class="c-dropdown__item dropdown-item" (click)="activeDeactivateUser(data?.Id, true); $event.preventDefault()" data-toggle="modal" data-target="#activate-member">Activate User</a>
</div>
As you can see I'm using prevent default, this does nothing, have tried
stop propagation but this stops the functions I want to execute from executing
Hopefully someone can point me in the right direction
You need to use stopPropagation() to stop the event from passing to parent DOM. You use preventDefault() to stop the default event action from being taken for the event object. For example, in the case of an anchor element, the default click action is to open the link, so if you wanted to implement a special check that prevents the link from being opened under a specific condition, you could use preventDefault() from within the (click) callback function to do that. But if you want to stop the click event from being passed to the parent element, you would use stopPropagation():
<span onclick="alert('You've already visited Stack Overflow')">
<a href="https://stackoverflow.com" (click)="visitStack($event)">
Stack Overflow
</a>
</span>
stackVisited = false;
visitStack(event) {
if (this.stackVisited) {
event.preventDefault();
} else {
this.stackVisited = true;
event.stopPropagation();
}
}
Related
I'm fairly new to Angular and need to solve what seems to be a simple problem: show an alert or confirmation message on navigating between tabs in angular bootstrap. the issue is when moving to another tab, the tab will open first and then show an alert message if clicked on cancel it will back to the previous tab, what I want simply is to not leave the current tab until click on confirmation to leave.
<ul ngbNav #navWithIcons="ngbNav" [(activeId)]="activeTab" class="nav-tabs">
<li ngbNavItem="docs">
<a ngbNavLink (click)="navigateTab('docs')">
<span [data-feather]="'file-text'"></span>Documents</a>
<ng-template ngbNavContent>
<p>
any content
</p>
</ng-template>
</li>
<li ngbNavItem="external">
<a ngbNavLink (click)="navigateTab('external')">
<span [data-feather]="'chrome'"></span> External
Resource</a>
<ng-template ngbNavContent>
<p>
any external link
</p>
</ng-template>
</li>
</ul>
<div [ngbNavOutlet]="navWithIcons" class="mt-2"></div>
TS:
navigateTab(navTab: string) {
if (navTab != this.currentTab) {
if (this.isInputUpdated) {//if there is an update on the current tab inputs then
this.confirmationMessage(true, this.currentTab);
this.isInputUpdated = false;
}
this.currentTab = navTab;
}
}
You can listen to navChange event on the ngbNav element and stop the event from propagating
<ul ngbNav #navWithIcons="ngbNav" [(activeId)]="activeTab" class="nav-tabs" (navChange)="navChanged($event)">
...
</ul>
navChanged(event) {
event.preventDefault()
}
Inside the confirmationMessage method, if clicked on confirm set active tab with the value of currentTab
We have a widget in ServiceNow where we have buttons that show pre-configured filters. The buttons work great onClick, but we would like the first button to be clicked and the first filter to be applied on load. Is there a way to initiate this on load? We tried using ng-init, but we couldn't get that to work.
<p><strong>Filters:</strong></p>
<button ng-if="options.show_preconfigured_filters=='true'"
class="btn btn-outline-primary pull-left m-r-sm m-b-sm"
ng-repeat="filters in data.preconfigured_filters | orderBy : 'order' track by $index"
ng-click="c.applyFilter(filters);">
<i class="glyphicon glyphicon-filter m-r-sm"></i>{
{filters.title}}
</button>
<div class="clearfix"></div>
c.applyFilter = function(filter) {
$scope.data.filter = filter.filter;
c.appendQuery($scope.data.filter);
}
One approach is to compute the ordered list in the controller:
var orderedList = $filter('orderBy')($scope.data.preconfigured_filters, 'order');
c.applyFilter(orderedList[0]);
This executes the same function that a user invokes by clicking the first item.
I have a table that the last column is a div where I have three options (View, Edit and delete). This sub menu is always hidden, but when I click in the options button that is the last column of my table, the array that I use to control what is showing is updated to true (it should be showing), but nothing happened in my page.
Here is my HTML code
<td class="kt-datatable__cell">
<span style="overflow: visible; position: relative; width: 197px;">
<center>
<div class="dropdown">
<a data-toggle="dropdown" class="btn btn-sm btn-clean btn-icon btn-icon-md" #click="toggleHover(index)"
v-bind:class="{'show': hover[index]}">
<i class="flaticon2-shield"></i>
</a>
<div v-bind:class="{'show': hover[index]}" class="dropdown-menu">
And here is my method that I call using #click
methods: {
toggleHover(index) {
this.hover[index] = !this.hover[index];
}
If I set true for a random position right after I get the data from the server, it shows, but when I try to change this by clicking, nothing happens.
It's a reactivity caveat, so you should do :
methods: {
toggleHover(index) {
this.$set(this.hover,index , !this.hover[index]);
}
I have this look-a-like code in my app :
let item;
$('.parent').on('click', function () {
item = $(this).attr('item') || 0;
});
$('.parent').on('click', '.children', this, function () {
doSomething();
});
<div class="parent" item="50">
<div class="children">
</div>
</div>
<div class="parent" item="51">
<div class="children">
</div>
</div>
<div class="parent" item="52">
<div class="children">
</div>
</div>
I have a parent element with several children in it. Clicking anywhere on the parent element will give me an item information, so I will be able to load functions according to this item variable on click on children.
My problem is : I have to delegate the onClick event on children to parent element otherwise the events will trigger in this order :
Click on any child
Click on parent, which is too late because I need item variable first
I have a functionality that replaces the parent element if activated, since it was dynamically inserted into the DOM, I have to delegate the onClick event as well, like this :
$('.grandParent').on('click', '.parent', function () {
item = $(this).attr('item') || 0;
});
Now my problem is that the events are triggering in the wrong order again :
Click on any child
Click on parent
How can I manage to set click event on parent as top priority?
Edit :
I will be more specific. I have a messages list on my page, each .message element contains the message content but also some functionnalities like edit, delete, set as favorite, like, etc.
Like this :
<div class="message" data-item="1">
<a class="edit">E</a>
<a class="delete">X</a>
<a class="favorite">Fav</a>
<a class="like">Like</a>
<div class="content">
Hello world !
</div>
</div>
<div class="message" data-item="2">
<a class="edit">E</a>
<a class="delete">X</a>
<a class="favorite">Fav</a>
<a class="like">Like</a>
<div class="content">
Hello world !
</div>
</div>
Each one of those functionnalities will trigger different functions when clicked : edit(), delete(), like(), etc.
All of them will make AJAX requests which will then send the item variable to my server in order to know what item has to be impacted by this click.
To avoid repetition in my events handlers, I am trying to get the data-item attribute's value with one event bound to click on .message element, relying on the bubbling of children elements.
Get the item where you actually want it and get rid of the handler on parent:
$('.parent').on('click', '.children', function () {
item = $(this).closest('.parent').attr('item');
doSomething();
});
EDIT:
Then get the item when you click on the grandparent:
$('.grandParent').on('click', '.children', function () {
item = $(this).closest('.parent').attr('item');
});
EDIT #2:
Based on the OPs updated requirements, do it like this:
<div class="message" data-item="1">
<a class="action edit" data-type="edit">E</a>
<a class="action delete" data-type="delete">X</a>
<a class="action favorite" data-type="favorite">Fav</a>
<a class="like">Like</a>
<div class="content">
Hello world !
</div>
</div>
<div class="message" data-item="2">
<a class="action edit" data-type="edit">E</a>
<a class="action delete" data-type="delete">X</a>
<a class="action favorite" data-type="favorite">Fav</a>
<a class="like">Like</a>
<div class="content">
Hello world !
</div>
</div>
$(document).on('click','.message .action',function(e) {
const item = $(this).closest('message').attr('item');
switch($(this).data('type')) {
case 'edit': doEdit(item); break;
case 'delete': doDelete(item); break;
case 'favorite': doFavorite(item); break;
}
});
See, one event handler?
It's a very common pattern to do what you're doing. In the absence of a more robust framework (e.g. React), then using plain jQuery this is how it should be done.
when I hide the popover and open it up again, the value of currentPage hasn't been changed.
HTML CODE:
<el-popover
placement="bottom"
trigger="click"
title="网段详情"
#hide="popoverHide">
<el-table :data="inner_table_data.slice((insidePage-1)*5,insidePage*5)" stripe height="100%">
<el-table-column></el-table-column>
</el-table>
<el-pagination
#current-change="insideChange"
:page-size="5"
layout="prev, pager, next"
:total="30">
</el-pagination>
<a href="javascript:;" slot="reference">
<span v-html="scope.row.subnet"></span>
</a>
</el-popover>
JS CODE:
popoverHide: function () {
this.insidePage = 1;
this.inner_table_data = '';
}
demo link is here: https://jsfiddle.net/npfL4e7h/10/
Change page number in pagination, hide it and open it up again, the data is the first page's data while page number is the number before hiding the popover. Adding a :current-page doesn't seem to help.
You need to add current-page property to the pagination.
<el-pagination
#current-change="insideChange"
:page-size="5"
layout="prev, pager, next"
:total="30"
:current-page="insidePage"
>