Link to home
Start Free TrialLog in
Avatar of -Dman100-
-Dman100-Flag for United States of America

asked on

Attaching click event to a JQuery object not yet added to the DOM

I have a button that adds table rows dynamically. On each button click I need to show/hide specific elements in the table row.

The first time the buttons is clicked, the first row is added in the table, but the table row has not been added to the DOM so I can't access the table row object.

First I tried this:

        j$('[id$=btnContact]').click(function(){
            console.log('contact button was clicked');
            var dataRows = j$('tr.dataRow');
            console.log(dataRows);
        });

Open in new window


Then I tried this:

            j$('[id$=btnContact]').on("click", function(){
                console.log('contact button was clicked');
                var dataRows = j$('tr.dataRow');
                console.log(dataRows);
            });

Open in new window


The problem is that the dataRows object is empty when the button is clicked because the first row of the table has not been added to the DOM.  

If I click the button again and a second row is added, then I have access to the first table row.  I need to access the row that is being created when the button is clicked.

How can I access the table row object when it is being created?

Thanks for any help.
Avatar of Rob
Rob
Flag of Australia image

Please show your code that inserts the row.
For dynamic elements you have to use .on as you are doing but the targeting object must be an element that exists at load and then you target your dynamic element.

j$('#existing_element_container_id').on("click", "target_element",function(){
...
This will fire for every row (and new ones after the DOM has loaded):

$("#dataTable tbody tr").on("click", function(event){
  alert($(this).text());
});

Open in new window


see the documentation http://api.jquery.com/on/ re Delegated events
You can do this too :
$(document).on("click", "[id$=btnContact]", function(event){
  alert($(this).text());
});

Open in new window


or just do the binding after your ajax call :
var oDBGet = new htmldb_Get(p1, p2, p3, p4);
gReturn = oDBGet.get(); // your ajax call
j$('[id$=btnContact]').click(function(){
            console.log('contact button was clicked');
            var dataRows = j$('tr.dataRow');
            console.log(dataRows);
        });

Open in new window

Avatar of -Dman100-

ASKER

Hi tagit,

I'm having to make some modifications to the code you helped with me previously.  After doing a review with the users, they wanted some  changes to how the page worked.

It has been a few weeks, but if you recall the jquery was hiding images depending on what input field was selected on each row.

So, the change I'm trying to make is the following.  The user wants there different buttons to create a new row for either a contact, user or account.  So, if the user clicks the "Add New Contact" button, it would only show the lookup for the contact input field.  If the user clicks the "Add New User" button, it would only show the lookup for the user input field. And finally, if the user clicks "Add New Account" button, it would only show the lookup for the account input field.  

Previously, the images were getting hidden after the row was generated and the input field was populated from the lookup.  The end users felt that was confusing and only want to see the one input field for the lookup they are trying to create.

I was trying to follow the code you helped me with, but the issue I was running into is that the table row hasn't been added to the DOM when the button is clicked.
I'll have a look back as i remember what you were working on :-) makes sense what you're saying just need to review the code.
I think the same logic still applies in that you use the:

A4J.AJAX.AddListener({
	onafterajax: function(req,evt,data) { 
		var dataRows = j$('tr.dataRow');
		dataRows.each(function(index, elem) {
			updateImages(elem);
		});
	}
});

Open in new window


What does the updateImages() function do now?
The updateImages() function is hiding the lookup icon images based on the input value that was populated.

Is there a way to determine which button was clicked from within that onafterajax code?

In this new scenario, I have to hide the input fields and lookup images based on which button was clicked.
The main difference now is that the elements are not hidden after the user selects a value from one of the lookups.  It should happen immediately based on the button that is clicked.

It prevents the user from being presented with all three inputs.  They click one of the buttons and it shows them just one input field for the lookup they are trying to do...i.e. Contact, User, or Account.

Thanks for taking a look at this code again! :)

I thought I had it nailed down tight!
The first thing that comes to mind is using a cookie, which is easily achieved with jQuery or using the localStorage object to keep track of the clicked button:

so when each button is clicked it sets the storage value

$('#mybuttonid').on('click', function() {
    localStorage.activeBtn = $(this).name;
});

Then you access that data in the updateImages function.  Can you post the latest version of that just to be sure as I don't have a copy of it.
Here is the current jquery code without any modifications:

    <script type="text/javascript"> 
        var j$ = jQuery.noConflict();

        j$(document).ready(function() {
            var dataRows = j$('tr.dataRow');
            
            dataRows.each(function(index, elem) {
                updateImages(elem);
            });
  
            j$("img[id$=':deleteImage']").on("click", function(event) {
                updateImages(j$(this).closest('tr'));
            });
            
            j$('[id$=btnParticipant]').on("click", function(event){
                var dataRows = j$('tr.dataRow');
                dataRows.each(function(index, elem) {
                    updateImages(elem);
                });
            });
            
            A4J.AJAX.AddListener({
                onafterajax: function(req,evt,data) { 
                    var dataRows = j$('tr.dataRow');
                    dataRows.each(function(index, elem) {
                        updateImages(elem);
                    });
                }
            });   
            
        });

        function updateImages(myRow) { 
            var rowInputs =  j$(myRow).find('input[type="text"]');
            var contact = (j$(rowInputs[0]).val()); 
            var user = (j$(rowInputs[1]).val());
            var account = (j$(rowInputs[2]).val());
  
            if (contact !== '') {
                j$(rowInputs[0].parentNode).find('img').show();
                j$(rowInputs[1].parentNode).find('img').hide();
                j$(rowInputs[2].parentNode).find('img').hide();
            }    
            else if (user !== '') {
            	if(rowInputs.length == 3) {
                	j$(rowInputs[0].parentNode).find('img').hide();
                	j$(rowInputs[1].parentNode).find('img').show();
                	j$(rowInputs[2].parentNode).find('img').hide();
                }
            }
            else if (account !== '') {
                j$(rowInputs[0].parentNode).find('img').hide();
                j$(rowInputs[1].parentNode).find('img').hide();
                j$(rowInputs[2].parentNode).find('img').show();
            }
            if (account !== '' && contact !== '') {
                j$(rowInputs[0].parentNode).find('img').show();
                j$(rowInputs[1].parentNode).find('img').hide();
                j$(rowInputs[2].parentNode).find('img').hide();
            }
        }
    </script>

Open in new window

oh, here are the new buttons:

<apex:commandButton id="btnContact" value="Add Contact" action="{!addParticipant}" reRender="participantTable" />
<apex:commandButton id="btnUser" value="Add ACI Employee" action="{!addParticipant}" reRender="participantTable" />
<apex:commandButton id="btnAccount" value="Add Company" action="{!addParticipant}" reRender="participantTable" />

Open in new window

So in the  javascript

j$(document).ready(function() {
...
$('#btnContact').on('click', function() {
    localStorage.activeButton = 'contact';
});

$('#btnUser').on('click', function() {
    localStorage.activeButton = 'user';
});

$('#btnAccount').on('click', function() {
    localStorage.activeButton = 'account';
});

Open in new window


Then in your updateImages, though I can't test this without access:
 function updateImages(myRow) { 
            var rowInputs =  j$(myRow).find('input[type="text"]');
            var contact = (j$(rowInputs[0]).val()); 
            var user = (j$(rowInputs[1]).val());
            var account = (j$(rowInputs[2]).val());
  
            if (localStorage.activeButton === 'contact') {
                        // hide the other two            
                        j$(rowInputs[1]).hide();
                        j$(rowInputs[2]).hide();
            }
            else if (localStorage.activeButton === 'user') {
                        // hide the other two            
                        j$(rowInputs[0]).hide();
                        j$(rowInputs[2]).hide();
            }
            else if (localStorage.activeButton === 'account') {
                        // hide the other two            
                        j$(rowInputs[0]).hide();
                        j$(rowInputs[1]).hide();
            }

            if (contact !== '') {
                j$(rowInputs[0].parentNode).find('img').show();
                j$(rowInputs[1].parentNode).find('img').hide();
                j$(rowInputs[2].parentNode).find('img').hide();
            }    
            else if (user !== '') {
            	if(rowInputs.length == 3) {
                	j$(rowInputs[0].parentNode).find('img').hide();
                	j$(rowInputs[1].parentNode).find('img').show();
                	j$(rowInputs[2].parentNode).find('img').hide();
                }
            }
            else if (account !== '') {
                j$(rowInputs[0].parentNode).find('img').hide();
                j$(rowInputs[1].parentNode).find('img').hide();
                j$(rowInputs[2].parentNode).find('img').show();
            }
            if (account !== '' && contact !== '') {
                j$(rowInputs[0].parentNode).find('img').show();
                j$(rowInputs[1].parentNode).find('img').hide();
                j$(rowInputs[2].parentNode).find('img').hide();
            }
        }
    </script>

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Rob
Rob
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Tagit helped me resolve this issue with the following updated code:

    <script type="text/javascript"> 
        var j$ = jQuery.noConflict();

        j$(document).ready(function() {
            var dataRows = j$('tr.dataRow');
            localStorage.activeButtons = '';
            var active = localStorage.activeButtons.split(',');
            dataRows.each(function(index, elem) {
                updateImages(elem, active[index]);
            });
  
            j$("img[id$=':deleteImage']").on("click", function(event) {
                updateImages(j$(this).closest('tr'));
            });
            
            j$('[id$=btnContact]').on('click', function() {
                localStorage.activeButtons += 'contact,';
            });
            
            j$('[id$=btnUser]').on('click', function() {
                localStorage.activeButtons += 'user,';
            });
            
            j$('[id$=btnAccount]').on('click', function() {
                localStorage.activeButtons += 'account,';
            });

            A4J.AJAX.AddListener({
                onafterajax: function(req,evt,data) { 
                    
                    var lastRow = j$('table[id$=participantTable] tbody tr:last');
                    
                    var active = localStorage.activeButtons.split(',');
                    
                    var dataRows = j$('tr.dataRow');
                    dataRows.each(function(index, elem) {
                        updateImages(elem, active[index]);
                    });
                }
            });   
            
        });

        function updateImages(myRow, myActive) { 
            var rowInputs =  j$(myRow).find('input[type="text"]');
            var contactId = (j$(rowInputs[0]).attr('id'));
            var userId = (j$(rowInputs[1]).attr('id'));
            var accountId = (j$(rowInputs[2]).attr('id'));
 
            console.log(myActive);
            if(contactId.indexOf("participant") != -1 || userId.indexOf("participant") != -1 || accountId.indexOf("participant") != -1) {
                switch (myActive) {
                    case "contact":
                        // hide the other two
                        j$(rowInputs[1]).hide();
                        j$(rowInputs[2]).hide();
                        j$(rowInputs[1].parentNode).find('img').hide();
                        j$(rowInputs[2].parentNode).find('img').hide();
                        break;
                    case "user":
                        // hide the other two
                        j$(rowInputs[0]).hide();
                        j$(rowInputs[2]).hide();
                        j$(rowInputs[0].parentNode).find('img').hide();
                        j$(rowInputs[2].parentNode).find('img').hide();
                        break;
                    case "account":
                        // hide the other two
                        j$(rowInputs[0]).hide();
                        j$(rowInputs[1]).hide();
                        j$(rowInputs[0].parentNode).find('img').hide();
                        j$(rowInputs[1].parentNode).find('img').hide();
                        break;
                }
            }
        }
    </script>

Open in new window


A million thanks to Tagit!
Thank you Tagit!  You are an exceptional expert here! :)