onhover need to get an icon at the end of a row

Hi Team,

I have couple of queries as mentioned in below images,

1. onhover i need to get an icon at the end of a row,please check below image


2. onclick of the corner icon, need to get an dropdown kind and that should have action items like add edit etc




3. I need an icon before the expand icon 
4. How can I add complex data binding like example

ex: name: {firstname:"",last:{name:"}} -> if I want to add last.name as a fieldname then how can i do it?
ex: employee[{},{}] -> if I want to display length of an employee array length then how I need to give that in field name?

Regards,
Bhavya

16 Replies

SK Sujith Kumar Rajkumar Syncfusion Team April 8, 2020 11:50 AM UTC

Hi Bhavya, 

Greetings from Syncfusion support. 

Query – 1: On hover i need to get an icon at the end of a row, please check below image 
Query – 2: On click of the corner icon, need to get an dropdown kind and that should have action items like add edit etc 

You can achieve these requirements by rendering the EJ2 Menu control with sub-menu items in the last grid column using its template property and on clicking the sub-menu items you can perform the required operations like add, edit using grid methods – addRecord, startEdit respectively. This is explained below, 

Initially render the EJ2 Menu control in the last grid column(And disable edit to this column using its allowEditing property) using template with the required sub-menu items(Add, Edit) on clicking which the corresponding actions can be performed. Then bind select event to the menu. 

app.component.html  
<ejs-grid #grid id='grid' (created)='onCreated($event)' allowPaging='true' [dataSource]='data' [editSettings]='editSettings' [toolbar]='toolbar'>  
    <e-columns>  
             . 
             . 
        <e-column headerText='Actions' width=150 [allowEditing]='false'>  
            <ng-template #template>  
                <div class='custom-menu'> 
                    <ejs-menu #menu [items]='menuItems' (select)='onSelect($event)'></ejs-menu>  
                </div> 
            </ng-template>  
        </e-column>  
    </e-columns>  
</ejs-grid>  

app.component.ts  
ngOnInit() {  
                .  
               .  
        // Menu items  
        this.menuItems = [  
            {  
                iconCss: 'e-icons MT_Menu',  
                items: [  
                    { text: 'Add', iconCss: 'e-icons Add' }, 
                    { text: 'Edit', iconCss: 'e-icons Edit' }  
                ]  
            }  
        ];  
}  

In the menu’s select event, if the selected item is ‘Add’, then invoke the Grid’s addRecord method to add a new record to the Grid. If the selected item is ‘Edit’, get the grid’s row index, select the row using selectRow method and enable edit using startEdit method.  

// Menu’s select event function  
onSelect(args) {  
     if (args.item.text === Add) {  
            // Adds a new record  
            this.grid.addRecord();  
     } else if (args.item.text === 'Edit') {  
            // Gets the grid row index based on the selected menu item  
            var gridRowIndex = parseInt(args.item.controlParent.lItem.closest('.e-row').getAttribute('aria-rowindex'));  
            // Selects the grid row  
            this.grid.selectRow(gridRowIndex);  
            // Enables edit for the selected row  
            this.grid.startEdit();  
     }  
}  

Icon styles for the menu items,  

// Icon for the parent menu item  
.MT_Menu::before {  
        content'\e984';  
}  
  
// Icon for add sub menu item  
.Add::before {  
        content'\e7f9';  
}  
 
// Icon for edit sub menu item  
.Edit::before {  
        content'\e81e';  
}  
  
// Removes the default caret icon displayed in the menu  
.e-menu-wrapper ul .e-menu-item .e-caret::before {  
        content'' !important;  
}  
  
// Adjusting position of the menu element  
.e-menu-wrapper {  
        margin-left11px;  
}  
  
// Modifying the width of the parent menu item  
.e-menu-wrapper ul.e-menu {  
        width20px;  
}  
  
// Adjusting the position of the parent menu icon  
.e-menu-wrapper ul.e-menu .e-menu-item {  
        padding-left3px;  
        padding-right3px;  
        width20px;  
}  

If you only want this menu icon to be displayed while hovering the row, then you can achieve this by setting visibility as ‘hidden’ to this menu’s parent element in the rowDataBound event and modifying this visibility property on ‘mouseenter’ and ‘mouseleave’ events on the row elements. This is demonstrated in the below code snippet, 

// Grid’s rowDataBound event function 
rowDataBound(args) { 
        // The menu is hidden initially using its parent element rendered in the column template 
        args.row.querySelector('.custom-menu').style.visibility = "hidden"; 
        // Mouse enter and leave events are bound to the row elements 
        args.row.addEventListener('mouseenter', function (args) { 
            // Menu is shown 
            args.target.querySelector('.e-menu-wrapper').style.visibility = "visible"; 
        }) 
        args.row.addEventListener('mouseleave', function (args) { 
            // Menu is hidden 
            args.target.querySelector('.e-menu-wrapper').style.visibility = "hidden"; 
        }) 
} 

For more details on the EJ2 Menu control you can check the below help documentation site, 


Query – 3: I need an icon before the expand icon 

This requirement can be achieved by dynamically creating and appending a div element with the icon class to each row in the Grid’s rowDataBound event(Triggers each time a row element is appended to the Grid element). To avoid header and content misalignment due to the new element added in the content, an empty element is added to the header row in the Grid’s dataBound event. This is demonstrated in the below code snippet, 

// Grid’s rowDataBound event function 
rowDataBound(args) { 
      // A new element is created and appended as first child to the row element 
      var tdEle = document.createElement('td'); 
      tdEle.innerHTML = '<div class="e-icons Custom-icon"></div>'; 
      args.row.insertBefore(tdEle, args.row.firstElementChild); 
} 
 
dataBound(args) { 
      var headertable = this.grid.element.querySelector('.e-columnheader'); 
      // A new element is created and appended as first child to the header element 
      var tdEle = document.createElement('td'); 
      tdEle.innerHTML = '<div></div>'; 
      headertable.insertBefore(tdEle, headertable.firstElementChild); 
} 

Icon styles added based on its class name. 

<style> 
    .Custom-icon:before { 
        content: '\e7f9'; 
    } 
</style> 

We have prepared a sample based on the above three queries for your reference which you can find below, 


Query – 4: How can I add complex data binding 

You can achieve complex data binding using the dot(.) operator in the field name. This is demonstrated in the below code snippet based on your field values, 

<e-column field='last.name' headerText='Name'></e-column> 

You can refer the below help documentation site for more details on this, 


Note: If the data is an array of objects then you need to access them like, “last.0.name”. You can refer the below help documentation for more details on this, 

Complex data binding with array of objects documentation: https://ej2.syncfusion.com/angular/documentation/grid/how-to/list-of-array-of-objects/ 

For displaying the array length in the column field you can specify its length like demonstrated in the below code snippet, 

<e-column field='employee.length' headerText='Length'></e-column> 

Please get back to us if you require any further assistance. 

Regards, 
Sujith R 



BH Bhavya Harini April 9, 2020 09:12 AM UTC

Hi Team,

Query – 3: I need an icon before the expand icon 

Regarding above query, i have added the given below code its fine but i need to manuplate the icon based on my api response

if my employee is inactive i need to show icon-x and if active i need to show icon-y, so i need to check my api response and then based on that i need to add the icon in front of each row. Please reply soon




BH Bhavya Harini April 9, 2020 09:51 AM UTC

Hi Team,

onhover im able to get icon but i should get below scenario, onclick of the icon i should get the dropdown as exact as below the icon should be exist. Please check below image as i need same UI for onclick action dropdown 





Regards,
Bhavya



BH Bhavya Harini April 9, 2020 10:28 AM UTC

Hi Team,

Please check the below code i have added action icons as last column and also icon on front of each row as you have suggested but we are getting spacing between each row and also while scrolling the table headers are moving to right.please check my sample code

html:

<ejs-grid #grid id='Grid' [dataSource]='rowData' (rowDataBound)='rowDataBound($event)' (dataBound)="dataBound($event)">

  <e-columns>
    <ng-container *ngFor="let column of def; index as i"> 
  
            <e-column *ngIf=" i == 0;else Show" [field]="column.tagName" [headerText]="column.tagLabel" [width]="column.tagWidth" [textAlign]="column.tagTextAlign"> 

              <ng-template #template let-data> 
                <div> 
                  <a rel='nofollow' rel='nofollow' rel='nofollow' href="">{{data[column.tagName]}}</a> 
                </div> 
               
              </ng-template> 
            </e-column> 
     
            <ng-template #Show> 
              <e-column [field]="column.tagName" [headerText]="column.tagLabel" [width]="column.tagWidth" [textAlign]="column.tagTextAlign"> 
              </e-column> 
            </ng-template> 
          
          </ng-container> 
          <e-column width=150   [allowEditing]='false'>  
            <ng-template #template>  
                <div class='custom-menu'> 
                    <ejs-menu #menu [items]='menuItems' (select)='onSelect($event)'></ejs-menu>  
                </div> 
            </ng-template>  
        </e-column>  
    
  </e-columns>
</ejs-grid>
App.ts

 ngOnInit() {
   
    this.rowData= this.items.items;
  
    const td = new TableDefinition(this.tableDefinition);
    this.def = td.tags.map(item => {

      return item;
    });
    this.filterOptions = {
      type: 'Menu'
    };
    this.menuItems = [  
      {  
          
          items: [  
              { text: 'Add' }, 
              { text: 'Edit' }  
          ]  
      }  
  ];  

    
  }
  // Grid’s rowDataBound event function 
rowDataBound(args) { 
  // The menu is hidden initially using its parent element rendered in the column template 
  args.row.querySelector('.custom-menu').style.visibility = "hidden"; 
  // Mouse enter and leave events are bound to the row elements 
  args.row.addEventListener('mouseenter', function (args) { 
      // Menu is shown 
      args.target.querySelector('.e-menu-wrapper').style.visibility = "visible"; 
  }) 
  args.row.addEventListener('mouseleave', function (args) { 
      // Menu is hidden 
      args.target.querySelector('.e-menu-wrapper').style.visibility = "hidden"; 
  }) 
 
    var tdEle = document.createElement('td'); 
    tdEle.innerHTML = '<span class="icon icon-Bell"></span>'; 
    args.row.insertBefore(tdEle, args.row.firstElementChild); 

 
}
dataBound(args) { 
  var headertable = this.grid.element.querySelector('.e-columnheader'); 
  // A new element is created and appended as first child to the header element 
  var tdEle = document.createElement('td'); 
  tdEle.innerHTML = '<div></div>'; 
  headertable.insertBefore(tdEle, headertable.firstElementChild); 

Thanks,
Bhavya


SK Sujith Kumar Rajkumar Syncfusion Team April 10, 2020 07:30 AM UTC

Hi Bhavya, 
 
Query – 1: Manipulate the icon based on my API response 
 
You can achieve this requirement by adding icon content for different classes and based on the API response remove the previous class and add the new icon class to update the icon. This is demonstrated in the below code snippet on button click function, 
 
app.component.ts 
// Button click event function 
iconChange(args) { 
      // Different icon classes that can be added to the Grid are retrieved 
      var customIconElements = this.grid.element.querySelectorAll('.Custom-icon'); 
      var updatedIconElements = this.grid.element.querySelectorAll('.Updated-icon'); 
      // Icon class is added and removed alternatively 
      // Here you can update based on your API response 
      if (customIconElements.length !== 0) { 
        customIconElements.forEach(x => x.classList.remove('Custom-icon')); 
        customIconElements.forEach(x => x.classList.add('Updated-icon')); 
      } else { 
        updatedIconElements.forEach(x => x.classList.remove('Updated-icon')); 
        updatedIconElements.forEach(x => x.classList.add('Custom-icon')); 
      } 
} 
 
app.component.css 
.Custom-icon:before { 
        content: '\e7f9'; 
} 
 
.Updated-icon:before { 
        content: '\e934'; 
} 
 
Query – 2: “Change sub-menu position” 
 
From your query and attached image we could see that you wish to modify the sub-menu element’s display position. You can achieve this by binding beforeOpen event to the menu and in that event you can change the menu position by modifying the arguments top and left values. We have demonstrated this in the below code snippet by modifying the sub-menu position based on the menu wrapper’s position, 
 
// Menu’s beforeOpen event function 
beforeOpen(args) { 
        var top = args.event.target.closest('.e-menu-wrapper').getBoundingClientRect().top; 
        var left = args.event.target.closest('.e-menu-wrapper').getBoundingClientRect().left; 
        args.top = top; 
        args.left = left; 
} 
 
This requirement is documented in our help documentation site in the below mentioned link which you can check for your reference, 
 
 
Query – 3: We are getting spacing between each row and also while scrolling the table headers are moving to right 
 
Sorry for the inconvenience. This problem was occurring due to the code in the dataBound event, as a ‘div’ element was getting inserted in the header row each time the dataBound was getting triggered. You can resolve this problem by executing this code only on initial render by using a flag variable. This is demonstrated in the below code snippet, 
 
export class AppComponent implements OnInit { 
           . 
           . 
    public initialRender = true; 
 
    dataBound(args) { 
        if (this.initialRender) { 
            var headertable = this.grid.element.querySelector('.e-columnheader'); 
            var tdEle = document.createElement('td'); 
            tdEle.innerHTML = '<div></div>'; 
            headertable.insertBefore(tdEle, headertable.firstElementChild); 
            this.initialRender = false; 
        } 
    } 
            . 
            . 
} 
 
We have modified the previously provided sample based on the above queries for your reference which you can find below, 
 
 
Let us know if you have any concerns. 
 
Regards, 
Sujith R 



BH Bhavya Harini April 13, 2020 10:23 AM UTC

HI Team,

While scrolling as the menu is hidden at the below line im getting below error

args.target.querySelector('.e-menu-wrapper').style.visibility = "hidden"; 

core.js:14597 ERROR TypeError: Cannot read property 'style' of null

Regards,
Bhavya


BH Bhavya Harini April 13, 2020 10:29 AM UTC

H Team,




I have my icon, onhover i'm placing the icon for each row.


Onclick of icon i need below behaviour, please provide proper solution

Note: icon should be on window n menu items and the window should be open left



Regards,
Bhavya


BH Bhavya Harini April 14, 2020 12:43 PM UTC

HI Team,

Can someone reply on it


SK Sujith Kumar Rajkumar Syncfusion Team April 14, 2020 01:02 PM UTC

Hi Bhavya, 
 
Query – 1: While scrolling as the menu is hidden error is occurring 
 
You can resolve this by checking if the target has the menu control and if so change its visibility style. 
 
args.row.addEventListener('mouseenter', function (args) { 
        if (args.target.querySelector('.e-menu-wrapper')) { 
            args.target.querySelector('.e-menu-wrapper').style.visibility = "visible"; 
        } 
}) 
 
args.row.addEventListener('mouseleave', function (args) { 
        if (args.target.querySelector('.e-menu-wrapper')) { 
            args.target.querySelector('.e-menu-wrapper').style.visibility = "hidden"; 
        } 
}) 
 
Query – 2: “Menu dropdown position” 
 
We are currently validating this query from our end. We will update the further details on 16th April 2020. Until then your patience is appreciated. 
 
Regards, 
Sujith R 



BH Bhavya Harini April 14, 2020 01:33 PM UTC

No Worries, i will use same menuitem what you have given above, but please make changes just onhover just move the dropdown on the hovered row and icon should be on it.just make these changes.It help me alot. 

Note: how can i chnage the drop down down arrow icon?

Regards,
Bhavya




SK Sujith Kumar Rajkumar Syncfusion Team April 15, 2020 09:23 AM UTC

Hi Bhavya, 

As informed in our previous update, our team is currently working on your query – “Changing menu dropdown position” and we will update the further details by 16th April 2020. 

For your other query how can i change the drop down arrow icon?, we suspect you mean the below menu icon, 

 

The icon class for this is set in the following line, 

this.menuItems = [ 
      { 
        iconCss: 'e-icons MT_Menu' 
      } 
]; 

And the corresponding icon content is set in the following CSS code, 

.MT_Menu::before { 
        content: '\e984'; 
} 

So if you are using an icon from the e-icons library you can just modify the icon content above. If you wish to render you own icon then you can set the required CSS class in the menu item’s iconCss property and set the corresponding icon content for that class in the CSS styles. 


Let us know if you have any concerns. 

Regards, 
Sujith R 



SK Sujith Kumar Rajkumar Syncfusion Team April 16, 2020 11:06 AM UTC

Hi Bhavya, 
 
Thanks for your patience. 
 
You can achieve the requirement – “Changing menu dropdown position with icon displayed on right side in the sub-menu” by modifying the menu’s left position in the beforeOpen event and setting float style to the icon property as demonstrated in the below code snippet, 
 
app.component.ts 
ngOnInit() { 
             . 
             . 
        this.menuItems = [ 
            { 
                iconCss: 'e-icons MT_Menu', 
                items: [ 
                    { text: 'Add', iconCss: 'e-icons MT_Menu' }, 
                    { text: 'Edit', iconCss: 'e-icons Edit1' } 
                ] 
            } 
        ]; 
} 
 
// Menu’s beforeOpen event 
beforeOpen(args) { 
        var top = args.event.target.closest('.e-menu-wrapper').getBoundingClientRect().top; 
        var left = args.event.target.closest('.e-menu-wrapper').getBoundingClientRect().left; 
        args.top = top; 
        args.left = left - 120; 
} 
 
app.component.css 
.MT_Menu::before { 
        content: '\e984'; 
} 
 
.e-menu-icon { 
        float: right; 
} 
 
Updated sample for your reference, 
 
 
Let us know if you have any concerns. 
 
Regards, 
Sujith R 



BH Bhavya Harini April 17, 2020 05:12 AM UTC

HI,

It is not helping,the menu is at same place it is not moving top and left


SK Sujith Kumar Rajkumar Syncfusion Team April 20, 2020 09:38 AM UTC

Hi Bhavya, 

With the code snippet we had provided in the last update, the dropdown menu was moved to the position you had requested for. Please check below video demo for your reference, 


We suspect the problem might be occurring due to cached memory in the browser causing old settings to be restored. So we suggest you to clear the local cache and then run your application to see if this resolves the problem. If you are using older Syncfusion packages we suggest you to update to the latest version. 

If your problem still persists please share us the following information to validate further, 

  • Video demo of the problem.
  • Grid code file.
  • If possible provide us a sample replicating the problem or try reproducing it in the sample we had provided.

Let us know if you have any concerns. 

Regards, 
Sujith R 



BH Bhavya Harini April 21, 2020 04:58 AM UTC

Hi Team,

Thanks a lot for your support. Its working fine now. But only last only one issue, if I release the onhover effect from row and move to Menu dropdown then onhover effect  is disappeared as we used mouseenter and mouseleave(check below code). Onhover of row should be appear still we move to dropdown. Please make this changes by EOD we have milestone

args.row.addEventListener('mouseenter'function (args) { 
        if (args.target.querySelector('.e-menu-wrapper')) { 
            args.target.querySelector('.e-menu-wrapper').style.visibility = "visible"; 
        } 
}) 
 
args.row.addEventListener('mouseleave'function (args) { 
        if (args.target.querySelector('.e-menu-wrapper')) { 
            args.target.querySelector('.e-menu-wrapper').style.visibility = "hidden"; 
        } 
}) 

QN2: 

    .e-grid .e-icon-grightarrow::before,
        .e-grid-menu .e-icon-grightarrow::before {
            content: '\e734';
        }
    .e-grid .e-icon-gdownarrow::before,
        .e-grid-menu .e-icon-gdownarrow::before {
            content: '\e705';
        }

I have used above code but still im not getting below icons, instead of that getting ChevronUp icon n ChevronDown icon





SK Sujith Kumar Rajkumar Syncfusion Team April 22, 2020 11:40 AM UTC

Hi Bhavya, 

We are glad to hear that the provided solution worked for you. 
 
Query – 1: Onhover of row should be appear still we move to dropdown. 
 
Since the Menu is a custom component rendered in the Grid columns, focusing on the menu items will not maintain hover on the Grid rows. However you can achieve this requirement by adding custom class to the row in the Menu’s beforeOpen and beforeClose event and then add the hover styles to this custom class. This is demonstrated in the below code snippet, 

app.component.html 
<ejs-menu #menu [items]='menuItems' (beforeClose)='beforeClose($event)' (beforeOpen)='beforeOpen($event)' (select)='onSelect($event)'></ejs-menu> 

app.component.ts 
beforeOpen(args) { 
      args.parentItem.parentObj.element.closest('.e-row').classList.add('custom-hover'); 
} 
 
beforeClose(args) { 
      args.parentItem.parentObj.element.closest('.e-row').classList.remove('custom-hover'); 
} 

app.component.css 
.custom-hover { 
        background-color: #eee; 
        color: #000; 
} 

 
Query – 2: I have used above code but still I’m not getting below icons, instead of that getting ChevronUp icon n ChevronDown icon 

We checked this problem from our end but the icons were properly rendered on using your code snippet in the application. Please check below image for your reference, 

 

We suspect the icon styles may not be reflected due to ViewEncapsulation enabled in your application causing the style to be scoped for particular components. So we suggest you to set the ViewEncapsulation to None to resolve this problem. 

@Component({ 
  selector: 'app-root', 
  templateUrl: './app.component.html', 
  styleUrls: ['./app.component.css'], 
  providers: [ToolbarService, DetailRowService], 
  encapsulation: ViewEncapsulation.None 
}) 


We have modified the previously provided sample based on the above queries. You can download it from the below link, 


Let us know if you have any concerns. 
  
Regards, 
Sujith R 


Loader.
Up arrow icon