I am roughly on latest AG/ID (14.2).
I have a data grid which represents scenarios (name, start, end, etc.) to which users want to add a field for comments (to describe purpose for oddly-suffixed scenario names). Adding the field is simple enough, but the intent is to use that comment as the mouse-hover text for the scenario name.
How is it that I set a mouse-hover text value for a field which is declared as below, and how to I reference the same row's comment field?
<igx-column [pinned]="true" field="name" header="Scenario Name" [dataType]="'string'" [resizable]="true" width="12%" [sortable]="true"> <ng-template igxCellEditor let-cell="cell"> <igx-input-group type="border"> <input igxInput [igxFocus]="true" [(ngModel)]="cell.editValue" (ngModelChange)="modelChange($event, cell, 'name')" displayDensity="compact" /> </igx-input-group> </ng-template> </igx-column>
Hello Chris,
Thank you for posting to Infragistics Community!
I have created this sample demostrating how the IgxGrid’s Cell Templating functionality can be leveraged in combination with the IgxTooltip capabilities to easily achieve your requirement.
The approach involves creating a cell display template that can be as simple as the default one, however, the element displaying the cell value has the addition of being set as a tooltip target. The same could be achieved for the cell editing template, of course. The tooltip reference template itself is defined within this cell template and displays a value from the exposed cell context:
<igx-column field="ProductName" header="Product Name" [dataType]="'string'"> <ng-template igxCell let-cell="cell" let-val let-row> <span #target="tooltipTarget" [igxTooltipTarget]="tooltipRef">{{ val }}</span> <div #tooltipRef="tooltip" igxTooltip> {{ cell.row.data.QuantityPerUnit }} </div> </ng-template> </igx-column>
I hope this suggestion helps. If you require any further assistance on the matter, please, let me know.
Best regards, Bozhidara Pachilova Associate Software Developer
I would love to say that worked, but I also need the input in that column and putting them together isn't working for me, either by meshing the tooltip code into the existing template or by adding another template to the same column.
It's using the scenario name as the tooltip, not the column value I'm attempting to designate.
Here is current code:
<igx-column [pinned]="true" field="name" header="Scenario Name" [dataType]="'string'" [resizable]="true" width="12%" [sortable]="true"> <ng-template igxCellEditor let-cell="cell" let-val let-row> <span #target="tooltipTarget" [igxTooltipTarget]="tooltipRef">{{ val }}</span> <div #tooltipRef="tooltip" igxTooltip> {{ cell.row.data.createdBy }} </div> <igx-input-group type="border"> <input igxInput [igxFocus]="true" [(ngModel)]="cell.editValue" (ngModelChange)="modelChange($event, cell, 'name')" displayDensity="compact" /> </igx-input-group> </ng-template> </igx-column>
Even removing the input code doesn't populate the right value for the tooltip: it's still just the scenario name. I assume I'm missing something in the .ts file, but I don't see anything that seems relevant.
Hi Chris,
Thank you for following up!
I have modified the previously referenced sample to also include a cell editing template with the same span and tooltip elements.
On my side everything is working as expected as the cell context provides info about the row and its data there as well and the tooltip correctly displays another column’s value. Could I ask you to please have a look at the sample again and eventually compare any discrepancies between it and your own template’s code? The only possible root cause I can currently think of is probably a typo in the data source’s filed name – “createdBy” as you have written.
Please, keep in mind, though, that I am not really familiar with your data model, such as what a “scenario name” represents, .etc.
By your description, I was under the impression it is a field in your data. In case I am missing an aspect of your requirement, please, provide further details on the same. If the information you would like to display in a tooltip cannot actually be found in the data record, maybe a getter/public field in the .ts file is indeed what has to be implemented. You could use the cellEditEnter event for instance, to extract information about the currently edited cell and set the value of this variable based on it.
Thank you for your cooperation.
I am unsure what I am doing wrong. I have tried using all columns and still only get mouse-hover of the scenario name. Here is my full HTML for the scenarios list page:
<div *ngIf="globals.scenarios !== [] && globals.scenarios.length > 0"> <igx-grid #scenarioList id="scenarioList" displayDensity="compact" [data]="globals.scenarios" [allowFiltering]="true" [allowAdvancedFiltering]="true" [primaryKey]="'id'" width="100%" height="{{ height - 132 }}px" [rowEditable]="globals.user.isContributor" (rowEdit)="rowEdit($event)" (onCellEditEnter)="cellEditStart($event)" (rowEditDone)="rowEditedDone($event)" [filterMode]="'excelStyleFilter'"> <igx-paginator [perPage]="25"></igx-paginator> <igx-grid-toolbar class="bg-primary"> <igx-grid-toolbar-title class="text-white"><b>Scenarios</b></igx-grid-toolbar-title> </igx-grid-toolbar> <ng-template igxRowEditText let-rowChangesCount> <span class="error" *ngIf="badName">{{ badNameWarning }}</span> </ng-template> <ng-template igxRowEditActions let-endRowEdit> <button igxButton igxRowEditTabStop (click)="endRowEdit(false)">Cancel</button> <button igxButton *ngIf="!badName" igxRowEditTabStop (click)="endRowEdit(true)">Done</button> </ng-template> <igx-column [pinned]="true" field="name" header="Scenario Name" [dataType]="'string'" [resizable]="true" width="12%" [sortable]="true"> <ng-template igxCellEditor let-cell="cell" let-val let-row> <span #target="tooltipTarget" [igxTooltipTarget]="tooltipRef">{{ val }}</span> <div #tooltipRef="tooltip" igxTooltip> {{ cell.row.data.active }} </div> <igx-input-group type="border"> <input igxInput [igxFocus]="true" [(ngModel)]="cell.editValue" (ngModelChange)="modelChange($event, cell, 'name')" displayDensity="compact" /> </igx-input-group> </ng-template> </igx-column> <igx-column field="active" header="Active" [resizable]="true" width="5%" [sortable]="true"> <ng-template igxCell let-cell="cell">{{ cell.value }}</ng-template> <ng-template igxCellEditor let-cell="cell" let-value> <igx-combo [(ngModel)]="cell.editValue" [data]="activeList" [igxFocus]="true" [overlaySettings]="customOverlaySettings" (selectionChanging)="singleSelection($event)" displayDensity="compact"></igx-combo> </ng-template> </igx-column> <igx-column field="scenarioType" header="Type" [resizable]="true" width="5%" [sortable]="true"> <ng-template igxCell let-cell="cell">{{ cell.value }}</ng-template> <ng-template igxCellEditor let-cell="cell" let-value> <igx-combo [(ngModel)]="cell.editValue" (ngModelChange)="modelChange($event, cell, 'type')" [data]="types" width="220px" [igxFocus]="true" (selectionChanging)="singleSelection($event)" [overlaySettings]="customOverlaySettings" [displayKey]="'name'" [valueKey]="'name'"></igx-combo> </ng-template> </igx-column> <igx-column field="startWw" header="Start WW" [dataType]="'string'" [resizable]="true" width="5%" [editable]="false" [sortable]="true"></igx-column> <igx-column field="endWw" header="End WW" [dataType]="'string'" [resizable]="true" width="5%" [editable]="false" [sortable]="true"></igx-column> <igx-column field="families" header="Family(s)" [dataType]="'string'" [resizable]="true" width="7%" [editable]="false" [sortable]="true"></igx-column> <igx-column field="facilities" header="Facility(s)" [dataType]="'string'" [resizable]="true" [editable]="false" [sortable]="true"></igx-column> <igx-column field="private" header="Private" [dataType]="'boolean'" width="5%" [resizable]="true"></igx-column> <igx-column field="locked" header="Locked" [dataType]="'boolean'" width="5%" [resizable]="true"></igx-column> <igx-column field="createdBy" header="Creator" [dataType]="'string'" width="5%" [resizable]="true" [editable]="false" [sortable]="true"> <ng-template igxCell let-value>{{ value.replace('sys_nsgplanning', 'SYSTEM') | uppercase }}</ng-template> </igx-column> <igx-column field="createdDate" header="Created (UTC)" [resizable]="true" width="8%" [editable]="false"> <ng-template igxCell let-value>{{ value + 'z' | date: 'MM/dd/yy hh:mm a' }}</ng-template> </igx-column> <igx-column field="lastModifiedBy" header="Updated By" [dataType]="'string'" [resizable]="true" width="5%" [editable]="false" [sortable]="true"> <ng-template igxCell let-value>{{ value.replace('sys_nsgplanning', 'SYSTEM') | uppercase }}</ng-template> </igx-column> <igx-column field="lastModifiedDate" header="Updated (UTC)" [resizable]="true" width="8%" [editable]="false"> <ng-template igxCell let-value>{{ value + 'z' | date: 'MM/dd/yy hh:mm a' }}</ng-template> </igx-column> <igx-column header="Actions" [filterable]="false" [editable]="false" [resizable]="true" width="340px" [sortable]="false"> <ng-template igxCell let-cell="cell" let-val> <div id="actionButtons"> <button [hidden]=" cell.row.data.scenarioType !== 'Actual' && globals.user.isContributor && !cell.row.data.locked && cell.row.data.active === 'Active' " igxButton (click)="goToScenario(cell.row.data.id, cell.row.data.name)" >View</button > <button [hidden]=" cell.row.data.scenarioType === 'Actual' || !globals.user.isContributor || cell.row.data.locked || cell.row.data.active === 'Archived' " igxButton (click)="goToScenario(cell.row.data.id, cell.row.data.name)" >Manage</button > <button [hidden]=" cell.row.data.scenarioType === 'Actual' || !globals.user.isContributor || cell.row.data.active === 'Archived' " igxButton (click)="setStartData(cell.row.data); copyScenario.open()" >Copy</button > <button [hidden]=" cell.row.data.scenarioType === 'Actual' || !globals.user.isContributor || cell.row.data.active === 'Archived' " igxButton (click)="archiveScenario(cell.row.data)" >Archive</button > <button [hidden]=" cell.row.data.scenarioType === 'Actual' || !globals.user.isContributor || cell.row.data.active === 'Active' " igxButton (click)="activateScenario(cell.row.data)" >Activate</button > <button [hidden]="cell.row.data.scenarioType === 'Actual' || !globals.user.isContributor || cell.row.data.locked" igxButton (click)="changeType(cell.row.data)" >Type</button > <button [hidden]="cell.row.data.scenarioType === 'Actual' || !globals.user.isAdmin" igxButton (click)="deleteScenario(cell.row.data)" >Delete</button > </div> </ng-template> </igx-column> </igx-grid> </div> <igx-dialog #copyScenario [closeOnOutsideSelect]="true"> <igx-dialog-title> <div class="dialog-title">Copy Scenario</div> </igx-dialog-title> <div *ngIf="scenario !== undefined && scenario.horizonId !== ''"> <igx-input-group> <igx-prefix>Name: </igx-prefix> <input igxInput style="width: 400px" id="scenName" type="text" (input)="validateName(scenario.scenarioType)" [(ngModel)]="scenario.name" displayDensity="compact" /> </igx-input-group> <br /> <span class="error" *ngIf="badNameCopy">{{ badNameCopyWarning }}</span> <div> <igx-input-group #scenTypeGroup [igxToggleAction]="scenType" displayDensity="compact"> <igx-prefix>Type: </igx-prefix> <input #scenTypeInput type="text" igxInput [igxDropDownItemNavigation]="scenType" readonly="true" [(ngModel)]="scenario.scenarioType" [value]="scenType.selectedItem?.value" (keydown.ArrowDown)="openDropDown('type')" /> <igx-suffix igxButton="icon" class="dropdownToggleButton" igxRipple> <igx-icon>arrow_drop{{ scenType.collapsed ? '_down' : '_up' }}</igx-icon> </igx-suffix> </igx-input-group> <igx-drop-down #scenType (selectionChanging)="validateName($event.newSelection.value)"> <div class="scrollable"> <igx-drop-down-item *ngFor="let type of types" [selected]="type.name === scenario.scenarioType" [value]="type.name">{{ type.name }}</igx-drop-down-item> </div> </igx-drop-down> </div> <div> <igx-input-group #startWwGroup [igxToggleAction]="startWwCopy" displayDensity="compact"> <igx-prefix>Start WW: </igx-prefix> <input #startWwCopyInput type="text" igxInput [igxDropDownItemNavigation]="startWwCopy" readonly="true" [(ngModel)]="scenario.startWw" [value]="startWwCopy.selectedItem?.value" (keydown.ArrowDown)="openDropDown('start')" /> <igx-suffix igxButton="icon" class="dropdownToggleButton" igxRipple> <igx-icon>arrow_drop{{ startWwCopy.collapsed ? '_down' : '_up' }}</igx-icon> </igx-suffix> </igx-input-group> <igx-drop-down #startWwCopy (selectionChanging)="logChange($event.newSelection.value, 'start')"> <div class="scrollable"> <igx-drop-down-item *ngFor="let ww of workweeks" [selected]="ww.id === scenario.startWwId" [value]="ww.id"> {{ ww.name }} </igx-drop-down-item> </div> </igx-drop-down> </div> <div> <igx-input-group #horizonGroup [igxToggleAction]="horizon" displayDensity="compact"> <igx-prefix>Horizon: </igx-prefix> <input #horizonInput type="text" igxInput [igxDropDownItemNavigation]="horizon" readonly="true" [(ngModel)]="scenHorizon" [value]="horizon.selectedItem?.value" (keydown.ArrowDown)="openDropDown('horizon')" /> <igx-suffix igxButton="icon" class="dropdownToggleButton" igxRipple> <igx-icon>arrow_drop{{ horizon.collapsed ? '_down' : '_up' }}</igx-icon> </igx-suffix> </igx-input-group> <igx-drop-down #horizon (selectionChanging)="logChange($event.newSelection.value, 'horizon')"> <div class="scrollable"> <igx-drop-down-item *ngFor="let ho of horizons" [selected]="ho.name === '5 Years'" [value]="ho.name">{{ ho.name }}</igx-drop-down-item> </div> </igx-drop-down> </div> <igx-combo #famCombo [data]="families" [width]="'200'" displayDensity="compact" [displayKey]="'name'" [(ngModel)]="selectedFamilies" (selectionChanging)="updateSelectedFamilies($event)"></igx-combo> <igx-combo #facCombo [data]="facilities" [width]="'200'" displayDensity="compact" [displayKey]="'name'" [(ngModel)]="selectedFacilities" (selectionChanging)="updateSelectedFacilities($event)"></igx-combo> <igx-checkbox id="privCheck" [(ngModel)]="scenario.private" labelPosition="before">Private: </igx-checkbox><br /> <button [disabled]="badNameCopy" igxButton="outlined" (click)="copyScenario.close(); createScenario()" ><igx-icon family="material">check</igx-icon><span>Add Scenario</span></button > <button igxButton="outlined" (click)="copyScenario.close()" ><igx-icon family="material">cancel</igx-icon><span>Cancel</span></button > </div> </igx-dialog> <igx-dialog #archiveConfirmation [closeOnOutsideSelect]="true" title="Confirmation" leftButtonLabel="Cancel" (leftButtonSelect)="onArchiveCancel()" rightButtonLabel="Confirm" (rightButtonSelect)="onArchiveConfirm()"> </igx-dialog> <igx-dialog #changeTypeDialog [closeOnOutsideSelect]="true"> <igx-dialog-title> <div class="title-container"> <div class="dialog-title">Change Scenario Type</div> </div> </igx-dialog-title> <div> <label igxLabel for="currentType">Current Scenario Type: </label> <br /> <b>{{ scenarioToChangeType?.scenarioType }}</b> </div> <div> <label igxLabel>New Scenario Type: </label> <br /> <igx-select #scenarioNewTypeSelect> <igx-select-item *ngFor="let item of typesForChangeType" [text]="item.name" [value]="item.id"> {{ item.name }} </igx-select-item> </igx-select> <span class="error" *ngIf="newTypeRequired">Please select the new type</span> </div> <div igxDialogActions> <button igxButton (click)="onChangeTypeCancel()">CANCEL</button> <button igxButton (click)="onChangeTypeConfirm()">Change Type</button> </div> </igx-dialog>
A scenario object looks like this:
export interface scenario { id: string; name: string; active: string; scenarioTypeId: string; scenarioType: string; startWw: string; startWwId: string; endWw: string; endWwId: string; private: boolean; locked: boolean; createdBy: string; createdDate: Date; lastModifiedBy: string; lastModifiedDate: any; facilities: string; families: string; facilityIds: string; familyIds: string; horizonId?: string; }
Validation is run on the Name based upon the scenarioType and retroactively applied if the user changes the scenarioType within a row or the copyScenario modal. Very simply, the Name must be in a format of
Thank you for sharing sample code. As far as the current discussion is concerned, I think only the “name” filed and its cell editor template code are relevant in this case, as well as the “scenario” interface having the “active” property.
At this point, I cannot identify anything wrong about this template. To verify it, I added it to the previously referenced sample’s “UnitPrice” column. By only modifying the accessed data property name to be any of the sample’s data properties, everything is working as expected and the tooltip shows the correct value of the expected data field. Please, check how it behaves in the sample:
The only thing I am wondering about concerning the code-snippet, is the fact that the “name” field in your grid is not marked as editable and the igxCellEditor sets just the editing template.
In conclusion, I am afraid I cannot give further suggestions on what else may be missing on your side, given that the isolated sample shows everything working as expected. My suggestion is to debug and verify that the target properties of the data are indeed defined. As usual, forking and modifying the StackBlitz sample to reproduce the behavior will be appreciated, so I can assist you further with the issue.
I figured it out.
Your sample has 2 `ng-template` components for the column and it only needs 1. I was using the wrong one. The igxCell template is the one I was missing, and the only one necessary for making the tooltip appear properly. I was attempting to include the tooltip component in the igxCellEditor template, which doesn't work.
To answer my second question above, "Yes, you can and need to declare a separate template for the tooltip inside the column declaration."
You indicated this implementation was correct and matched your example, but it was wrong:
<ng-template igxCellEditor let-cell="cell" let-val let-row> <span #target="tooltipTarget" [igxTooltipTarget]="tooltipRef">{{ val }}</span> <div #tooltipRef="tooltip" igxTooltip> {{ cell.row.data.active }} </div> <igx-input-group type="border"> <input igxInput [igxFocus]="true" [(ngModel)]="cell.editValue" (ngModelChange)="modelChange($event, cell, 'name')" displayDensity="compact" /> </igx-input-group> </ng-template>
On the other hand, this code is a match for what you have shown in the example, and actually works for me:
<ng-template igxCell let-cell="cell" let-val let-row> <span #target="tooltipTarget" [igxTooltipTarget]="tooltipRef">{{ val }}</span> <div #tooltipRef="tooltip" igxTooltip> {{ cell.row.data.active }} </div> </ng-template> <ng-template igxCellEditor let-cell="cell"> <igx-input-group type="border"> <input igxInput [igxFocus]="true" [(ngModel)]="cell.editValue" (ngModelChange)="modelChange($event, cell, 'name')" displayDensity="compact" /> </igx-input-group> </ng-template>
Thank you for your assistance. I think we both got caught by tunnel-vision and redundancy trap, looking at this too many times without seeing what was actually different.
I am glad that your issue is resolved. Thank you for using Infragistics components.
Best regards,
Bozhidara Pachilova