Custom renderer not detecting NULL

Tags: #<Tag:0x00007efc65284570> #<Tag:0x00007efc65284430>

Hey!
I have a small issue with making my custom renderer work like I want it to. The issue I have is with the same project as my previously posted question.

I have a table with about 500 data rows. The table is recording input from all employees of the organization about their New year resolution for the first half of the next year.
Columns in the table:

  1. Employee Name
  2. ID
  3. Resolution name
  4. Resolution update (after 3 months)
  5. Final result
  6. Ranking and
  7. Three more columns with “LIKE BUTTON” (each for Resolution name, update and final result).

LIKE BUTTON is similar to Instagram likes and is displayed as a division using inneHTML. My custom renderer is working fine to get the data and render the table.

But if my input field is NULL, the LIKE BUTTON is not going to be visible (which is also working correctly) and if I click into the cell to type value in it; I need to press a separate SAVE BUTTON to send it to the database. However, if I don’t press the SAVE BUTTON and move to a different cell (the input data exists as temporary data in all fields which got data entered into them) the LIKE BUTTON becomes visible and can store data which is becoming a huge problem. I checked all my backend files and it seems like it is an issue with the Handsontable rendering.

My Renderer:

 function detailRenderer(instance, td, row, col, prop, value, cellProperties) {
 		if (col == 5) {
 			if (value != null && instance.getDataAtCell(row, 9) != 0){
 				if(instance.getDataAtCell(row, 13)!= 0) {
 					Handsontable.renderers.TextRenderer.apply(this, arguments);
 					td.innerHTML = '<div class="like" id="like">'+value + '<div class="in-like"  id="in-like" style="color:red; text-align:center;"><i class="fas fa-heart" data-type="goalLikes" id="goalLikesButton'+row+'" data-id="goalLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i>' + instance.getDataAtCell(row, 9) + '</div></div>';
 				}
 				else {
 					Handsontable.renderers.TextRenderer.apply(this, arguments);
 					td.innerHTML = '<div class="like" id="like">'+value + '<div class="in-like" id="in-like" style="color:red; text-align:center;"><i class="far fa-heart" data-type="goalLikes" id="goalLikesButton'+row+'" data-id="goalLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i>' + instance.getDataAtCell(row, 9) + '</div></div>';
 				}
 			}
 			else if(value != null && instance.getDataAtCell(row, 9) == 0){
 				Handsontable.renderers.TextRenderer.apply(this, arguments);
 				td.innerHTML =   '<div class="like" id="like">'+value+'<div class="in-like" id="in-like" style="color:red; text-align:center;"><i class="far fa-heart" data-type="goalLikes" id="goalLikesButton'+row+'" data-id="goalLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i></div></div>';
 			}
 			else{
 				Handsontable.renderers.TextRenderer.apply(this, arguments);
 			}
 		}
 		else if (col == 6) {
 			if (value != null && instance.getDataAtCell(row, 10) != 0){
 				if(instance.getDataAtCell(row, 14)!= 0) {
 					Handsontable.renderers.TextRenderer.apply(this, arguments);
 					td.innerHTML = '<div class="like">'+value + '<div class="in-like" id="in-like" style="color:red; text-align:center;"><i data-type="replyLikes" id="replyLikesButton'+row+'" class="fas fa-heart" data-id="replyLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i>' + instance.getDataAtCell(row, 10) + '</div></div>';
 				}
 				else {
 					Handsontable.renderers.TextRenderer.apply(this, arguments);
 					td.innerHTML = '<div class="like">'+value + '<div class="in-like" id="in-like" style="color:red; text-align:center;"><i data-type="replyLikes" id="replyLikesButton'+row+'" class="far fa-heart" data-id="replyLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i>' + instance.getDataAtCell(row, 10) + '</div></div>';
 				}
 			}
 			else if(value != null && instance.getDataAtCell(row, 10) == 0){
 				Handsontable.renderers.TextRenderer.apply(this, arguments);
 				td.innerHTML = '<div class="like">'+value+'<div class="in-like" id="in-like" style="color:red; text-align:center;"><i data-type="replyLikes" id="replyLikesButton'+row+'" class="far fa-heart" data-id="replyLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i></div></div>';
 			}
 			else{
 				Handsontable.renderers.TextRenderer.apply(this, arguments);
 			}
 		}
 		else if (col == 8) {
 			if (value != null && instance.getDataAtCell(row, 11) != 0){
 				if(instance.getDataAtCell(row, 15)!= 0) {
 					Handsontable.renderers.TextRenderer.apply(this, arguments);
 					td.innerHTML = '<div class="like">'+value + '<div class="in-like" id="in-like" style="color:red; text-align:center;"><i data-type="resultLikes" id="resultLikesButton'+row+'" class="fas fa-heart" data-id="resultLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i>' + instance.getDataAtCell(row, 11) + '</div></div>';
 				}
 				else {
 					Handsontable.renderers.TextRenderer.apply(this, arguments);
 					td.innerHTML = '<div class="like">'+value + '<div class="in-like" id="in-like" style="color:red; text-align:center;"><i data-type="resultLikes" id="resultLikesButton'+row+'" class="far fa-heart" data-id="resultLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i>' + instance.getDataAtCell(row, 11) + '</div></div>';
 				}
 			}
 			else if(value != null && instance.getDataAtCell(row, 11) == 0){
 				Handsontable.renderers.TextRenderer.apply(this, arguments);
 				td.innerHTML = '<div class="like">'+value+'<div class="in-like" id="in-like" style="color:red; text-align:center;"><i data-type="resultLikes" id="resultLikesButton'+row+'" class="far fa-heart" data-id="resultLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i></div></div>';
 			}
 			else{
 				Handsontable.renderers.TextRenderer.apply(this, arguments);
 			}
 		} 
 		else{
 			Handsontable.renderers.TextRenderer.apply(this, arguments);
 		}
 		
 	}

My Handsontable:

hot = new Handsontable(container, {
    licenseKey: 'non-commercial-and-evaluation',
		data: data,
		height: $(window).height(),
		{% if(window.width() > 1350) %}
			width: $(window).width()-220,
		{% else %}
			width: $(window).width(),
		{% endif %}
		manualRowResize: true,
		rowHeaders: true,
		rowHeights: 50,
		className: 'htMiddle',
		renderer: detailRenderer,
		fillHandle: false,
		preventScrolling: false,
		hiddenColumns: {columns: [0,9,10,11,12, 13, 14, 15]},
        filters: true,
        dropdownMenu: ['filter_by_condition', 'filter_by_value', 'filter_action_bar'],
		columns: [	
			{data:'KEY',				 	title:'', width:50, readOnly:true},
			{data:'RANK',	    	        title:'RANK', width:70, type:'dropdown', source:[' ','🥇','🥈','🥉']},
			{data:'SYACD',	    	        title:'USERID', readOnly:true, width:100},
		    {data:'SYANM',			        title:'USERNAME', width:145, readOnly:true},
		    {data:'AFFILIATION',			title:'DESIGNATION', width:253, readOnly:true},
		    {data:'GOAL_COMMIT',			title:'NEW YEAR RESOLUTION', width:325, readOnly:true},
		    {data:'REPLY_COMMENT',	    	title:'HALF-TIME COMMENT', width:325, readOnly:true},
		    {data:'RESULT',	    	        title:'RESULT', width:70, readOnly:true, source: [' ','⭕', '✖️']},
		    {data:'GOAL_COMMENT',	    	title:'FINAL COMMENT', width:325, readOnly:true},
			
			{data:'GOAL_COMMIT_LIKES'},
			{data:'REPLY_COMMENT_LIKES'},
			{data:'GOAL_COMMENT_LIKES'},
			{data: 'SYACD'},
			{data: 'GOAL1'},
			{data: 'GOAL2'},
			{data: 'GOAL3'},
		], 
        afterChange: getChangedRows,
		afterGetRowHeader: function(col, TH) {
     		TH.className = 'htMiddle'
    	},
		cells: function (row, col) {
			var cellProperties = {};
		    cellProperties.renderer = detailRenderer;
		    return cellProperties;
			
		}
	});

Kindly let me know if I need to explain anything else. Thanks.

Hi @param556

This seems like a case for the afterChange() hook. I see that you already have a variable called getChangedRows, but it’s not in the code sample. Could you send it?

Yeah sure!
Here you go,

> function getChangedRows(changes) {
>         if(changes == null) {
>             return;
>         }
>         changes.forEach(([row, prop, oldValue, newValue]) => {
>             if(oldValue != newValue){
>                 let ID = hot.getDataAtRowProp(row,"SYANM");
>                 changeList.push(ID);
>             }
>         });
>     }

Hey! Apparently, browsing on this forum enough is making me dream solutions.

I figured out the answer. This is what I did to my renderer and it worked.

function detailRenderer(instance, td, row, col, prop, value, cellProperties) {
        if (col == 5) {
            if ((value != null && instance.getDataAtCell(row, 9) != 0)){
                    if(value !='' && instance.getDataAtCell(row, 13)!= 0) {
                        Handsontable.renderers.TextRenderer.apply(this, arguments);
                        td.innerHTML = '<div class="like">'+value + '<div class="in-like" style="color:red; text-align:center;"><i data-type="goalLikes" id="goalLikesButton'+row+'" class="fas fa-heart" data-id="goalLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i>' + instance.getDataAtCell(row, 9) + '</div></div>';
                    }
                    else if(value !='' && instance.getDataAtCell(row, 13)== 0){
                        Handsontable.renderers.TextRenderer.apply(this, arguments);
                        td.innerHTML = '<div class="like">'+value + '<div class="in-like" style="color:red; text-align:center;"><i data-type="goalLikes" id="goalLikesButton'+row+'" class="far fa-heart" data-id="goalLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i>' + instance.getDataAtCell(row, 9) + '</div></div>';
                    }
            }
            else if(value != null && instance.getDataAtCell(row, 9) == 0){
                if(value!=''){
                    Handsontable.renderers.HtmlRenderer.apply(this, arguments);
                    td.innerHTML =   '<div class="like">'+value+'<div class="in-like" style="color:red; text-align:center;"><i data-type="goalLikes" id="goalLikesButton" class="far fa-heart" data-id="goalLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row,12)+'" onclick="likesFunction(this)" ></i></div></div>';
                }
            }
            else{
                if(value!=''){
                    Handsontable.renderers.HtmlRenderer.apply(this, arguments);
                }
            }
        }
        else if (col == 6) {
            if (value != null && instance.getDataAtCell(row, 10) != 0){
                if(value !='' && instance.getDataAtCell(row, 14)!= 0) {
                        Handsontable.renderers.TextRenderer.apply(this, arguments);
                        td.innerHTML = '<div class="like">'+value + '<div class="in-like" style="color:red; text-align:center;"><i data-type="replyLikes" id="replyLikesButton'+row+'" class="fas fa-heart" data-id="goalLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i>' + instance.getDataAtCell(row, 10) + '</div></div>';
                    }
                    else if(value !='' && instance.getDataAtCell(row, 14)== 0){
                        Handsontable.renderers.TextRenderer.apply(this, arguments);
                        td.innerHTML = '<div class="like">'+value + '<div class="in-like" style="color:red; text-align:center;"><i data-type="replyLikes" id="replyLikesButton'+row+'" class="far fa-heart" data-id="goalLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i>' + instance.getDataAtCell(row, 10) + '</div></div>';
                    }
            }
            else if(value != null && instance.getDataAtCell(row, 10) == 0){
                if(value!=''){
                    Handsontable.renderers.TextRenderer.apply(this, arguments);
                    td.innerHTML = '<div class="like">'+value+'<div class="in-like" style="color:red; text-align:center;"><i data-type="replyLikes" id="replyLikesButton'+row+'" class="far fa-heart" data-id="replyLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row,12)+'" onclick="likesFunction(this)" ></i></div></div>';
                }
            }
            else{
                if(value!=''){
                    Handsontable.renderers.TextRenderer.apply(this, arguments);
                }
            }
        }
        else if (col == 8) {
            if (value != null && instance.getDataAtCell(row, 11) != 0){
                if(value !='' && instance.getDataAtCell(row, 15)!= 0) {
                    Handsontable.renderers.TextRenderer.apply(this, arguments);
                    td.innerHTML = '<div class="like">'+value + '<div class="in-like" style="color:red; text-align:center;"><i data-type="resultLikes" id="resultLikesButton'+row+'" class="fas fa-heart" data-id="goalLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i>' + instance.getDataAtCell(row, 11) + '</div></div>';
                }
                else if(value !='' && instance.getDataAtCell(row, 15)== 0){
                    Handsontable.renderers.TextRenderer.apply(this, arguments);
                    td.innerHTML = '<div class="like">'+value + '<div class="in-like" style="color:red; text-align:center;"><i data-type="resultLikes" id="resultLikesButton'+row+'" class="far fa-heart" data-id="goalLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row, 12)+'" onclick="likesFunction(this)"></i>' + instance.getDataAtCell(row, 11) + '</div></div>';
                }
            }
            else if(value != null && instance.getDataAtCell(row, 11) == 0){
                if(value!=''){
                    Handsontable.renderers.TextRenderer.apply(this, arguments);
                    td.innerHTML = '<div class="like">'+value+'<div class="in-like" style="color:red; text-align:center;"><i data-type="resultLikes" id="resultLikesButton'+row+'" class="far fa-heart" data-id="resultLikesButton'+row+'" data-userid="'+instance.getDataAtCell(row,12)+'" onclick="likesFunction(this)" ></i></div></div>';
                }
            }
            else{
                if(value!=''){
                    Handsontable.renderers.TextRenderer.apply(this, arguments);
                }
            }
        }
        else{
            Handsontable.renderers.TextRenderer.apply(this, arguments);
        }
    }

Thanks a lot for your constant help guys!

That sounds great, @param556!
I’m more than happy to hear that you found the solution.

1 Like

Hey! You mentioned the afterChange() approach as well for this. I have finished my work and am stuck somewhere else. I was wondering if you could give me a demo of how you would use afterChange() in this scenario.

Thanks!

And what do you say for a call? I think it will help us understand the projects’ mechanics and how things are connected. If you like the idea please share your availability with us at support@handsontable.com.

Sure! What all information would you need?

Your availability (in a given time zone) and the company you work for (or your license details)

This is more of a pet project so I’ll try my own fix for now and just upload any issues if I have in the future. Thanks!

OK, I understand. If something serious appears please feel free to request the call

1 Like