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.
-Dman100-Software ConsultantAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

RobOwner (Aidellio)Commented:
Please show your code that inserts the row.
0
GaryCommented:
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(){
...
0
RobOwner (Aidellio)Commented:
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
0
JavaScript Best Practices

Save hours in development time and avoid common mistakes by learning the best practices to use for JavaScript.

leakim971PluritechnicianCommented:
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

0
-Dman100-Software ConsultantAuthor Commented:
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.
0
RobOwner (Aidellio)Commented:
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.
0
RobOwner (Aidellio)Commented:
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?
0
-Dman100-Software ConsultantAuthor Commented:
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.
0
-Dman100-Software ConsultantAuthor Commented:
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!
0
RobOwner (Aidellio)Commented:
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.
0
-Dman100-Software ConsultantAuthor Commented:
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

0
-Dman100-Software ConsultantAuthor Commented:
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

0
RobOwner (Aidellio)Commented:
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

0
RobOwner (Aidellio)Commented:
After some testing I've updated this for you.  The localStorage didn't accept an array as a variable so it's now a comma separated string that I split.  This IDs what each row should be ie 'contact', 'user' or 'account'
Now I haven't built into this if the user deletes the row but that might be for later...  you'd essentially split the row, remove the corresponding index from the array as to the row you've removed before joining it up again and assigning the string to the localStorage object.
Also condensed your updateImages function to now use a switch statement.

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) { 
                    
                    // this isn't needed but IDs the last inserted row if you need it later
                    //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]);
                    });
                }
            });   
            
        });

Open in new window


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;
                }
                }
        }

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
-Dman100-Software ConsultantAuthor Commented:
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!
0
-Dman100-Software ConsultantAuthor Commented:
Thank you Tagit!  You are an exceptional expert here! :)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
jQuery

From novice to tech pro — start learning today.