0

I'm trying to assembly 3 JavaScript/jQuery parts in one and I can't do that. Basically I have a div#familyMembersList where we have a collection of family members. The collection is created from a data-prototype.

In this data-prototype I have 2 other collections div#addressList and div#mediasList that are created only when we click on a button that will create a family member. Then on every family member I need to add a add button to add an address and a media.

The problem is that as the div#addressList and div#mediasList doesn't exist when we click on the add family member button I can't add addresses and medias to the family member.

I can't paste the data-prototype that is too big but it's like

<div class="row">
    <div id="familyMembersList" data-prototype="
    ...
    <div id="addressList" data-prototype="">...</div>
    <div id="mediasList" data-prototype="">...</div>
    ...
">
    <p class="centered"><a href="#" class="add_fmember_link">Add family member</a></p>
    </div>
</div>

And my 3 js files are : 1)

var familyCollectionHolder;

// Set up an "add address" link
var addFMemberLink = $('<a href="#" class="add_fmember_link">Add family member</a>');
var newFamilyLinkP = $('<p class="centered"></p>').append(addFMemberLink);

function addFmemberForm(familyCollectionHolder, newFamilyLinkP){
    // Get the data prototype
    var prototype = familyCollectionHolder.data('prototype');

    // get the new index
    var index = familyCollectionHolder.data('index');

    // Replace '__name__' in the prototype's HTML
    //instead be a number based on how many items we have
    var newForm = prototype.replace(/__name__/g, index);

    // Increase the index with one for the new item
    familyCollectionHolder.data('index', index+1);

    //Display the form in the page nan li, before the "add address" link
    var newFormP = $('<div class="one-fmember"></div>').append(newForm);
    newFamilyLinkP.before(newFormP);
    addFMemberDeleteLink(newFormP);
}

function addFMemberDeleteLink(fmemberFormP)
{
    var removeFormP = $('<p class="centered"><a href="#" style="color:red">Delete member</a></p>');
    fmemberFormP.append(removeFormP);
    removeFormP.on('click', function(e){
         e.preventDefault();
         fmemberFormP.remove();
    })
}

jQuery(document).ready(function(){
    // Get the div that holds the collection of addresses
    familyCollectionHolder = $('div#familyMembersList');
    // add a delete link to all of the existensing forms
    familyCollectionHolder.find('div.one-fmember').each(function(){
        addFMemberDeleteLink($(this));
    });
    // add the "add address" anchor
    familyCollectionHolder.append(newFamilyLinkP);
    // Count the current form inputs
    // use that as the new index when inserting a new item
    familyCollectionHolder.data('index', familyCollectionHolder.find(':input').length);

    addFMemberLink.on('click', function(e)
    {
        // Prevent the link from creating a "#" on the URL
        e.preventDefault();
        // add a new address form
        addFmemberForm(familyCollectionHolder, newFamilyLinkP);
    })
});

2)

var collectionHolder;

// Set up an "add address" link
var addAddressLink = $('<a href="#" class="add_address_link">Add address</a>');
var newLinkP = $('<p class="centered"></p>').append(addAddressLink);

function addAddressForm(collectionHolder, newLinkP){
    // Get the data prototype
    var prototype = collectionHolder.data('prototype');

    // get the new index
    var index = collectionHolder.data('index');

    // Replace '__name__' in the prototype's HTML
    //instead be a number based on how many items we have
    var newForm = prototype.replace(/__name__/g, index);

    // Increase the index with one for the new item
    collectionHolder.data('index', index+1);

    //Display the form in the page nan li, before the "add address" link
    var newFormP = $('<div class="one-address"></div>').append(newForm);
    newLinkP.before(newFormP);
    addAddressDeleteLink(newFormP);
}

function addAddressDeleteLink(AddressFormP)
{
    var removeForm = $('<p class="centered"><a href="#" style="color:red">Delete Address</a></p>');
    AddressFormP.append(removeForm);

    removeForm.on('click', function(e){
        e.preventDefault();

        AddressFormP.remove();
    });
}

jQuery(document).ready(function(){
    // Get the div that holds the collection of addresses
    collectionHolder = $('div#addressList');

    // add the "add address" anchor
    collectionHolder.append(newLinkP);

    // add a delete link to all of the existing media form elements
    collectionHolder.find('div#one-address').each(function(){
        addAddressDeleteLink($(this))
    });

    // Count the current form inputs
    // use that as the new index when inserting a new item
    collectionHolder.data('index', collectionHolder.find(':input').length);
    addAddressLink.on('click', function(e)
    {
        // Prevent the link from creating a "#" on the URL
        e.preventDefault();
        // add a new address form
        addAddressForm(collectionHolder, newLinkP);
    })
});

3)

var collectionHolder2;

// Set up an "add address" link
var addMediaLink = $('<a href="#" class="add_media_link">Add Contact mean</a>');
var newLinkP2 = $('<p class="centered"></p>').append(addMediaLink);

function addMediaForm(collectionHolder, newLinkP2){
    // Get the data prototype
    var prototype = collectionHolder.data('prototype');

    // get the new index
    var index = collectionHolder.data('index');

    // Replace '__name__' in the prototype's HTML
    //instead be a number based on how many items we have
    var newForm = prototype.replace(/__name__/g, index);

    // Increase the index with one for the new item
    collectionHolder.data('index', index+1);

    //Display the form in the page nan li, before the "add address" link
    var newFormP = $('<div class="one-media"></div>').append(newForm);
    newLinkP2.before(newFormP);
    addMediaDeleteLink(newFormP);
}

function addMediaDeleteLink(mediaFormP)
{
    var removeForm = $('<p class="centered"><a href="#" style="color:red">Delete Media</a></p>');
    mediaFormP.append(removeForm);

    removeForm.on('click', function(e){
        e.preventDefault();

        mediaFormP.remove();
    });
}

jQuery(document).ready(function(){
    // Get the div that holds the collection of addresses
    collectionHolder2 = $('div#mediasList');

    // add the "add address" anchor
    collectionHolder2.append(newLinkP2);

    // add a delete link to all of the existing media form elements
    collectionHolder2.find('div#one-media').each(function(){
        addMediaDeleteLink($(this))
    });

    // Count the current form inputs
    // use that as the new index when inserting a new item
    collectionHolder2.data('index', collectionHolder2.find(':input').length);
    addMediaLink.on('click', function(e)
    {
        // Prevent the link from creating a "#" on the URL
        e.preventDefault();
        // add a new address form
        addMediaForm(collectionHolder2, newLinkP2);
    })
});

And the problem is that when we click on the addFmemberLink the div#addressList and div#mediasList doen't exist so I can't add addresses and medias to the created family member. Thank you !

EDIT : Ok, thanks to you guys I've found a way to make this work (I thought :( ) ! I paste my Frankenstein code if it may help someone : So I did functions to make it easier. And then when we click on 'add family member' I create the vars that will show the 'add address' and 'add media' links and then we can work. Welcome mr Frankenstein !

/* ADD ADDRESS */

function addAddressForm(collectionHolder, newLinkP){
    // Get the data prototype
    var prototype = collectionHolder.data('prototype');

    // get the new index
    var index = collectionHolder.data('index');

    // Replace '__name__' in the prototype's HTML
    //instead be a number based on how many items we have
    var newForm = prototype.replace(/__name__/g, index);

    // Increase the index with one for the new item
    collectionHolder.data('index', index+1);

    //Display the form in the page nan li, before the "add address" link
    var newFormP = $('<div class="one-address"></div>').append(newForm);
    newLinkP.before(newFormP);
    addAddressDeleteLink(newFormP);
}

function addAddressDeleteLink(AddressFormP)
{
    var removeForm = $('<p class="centered"><a href="#" style="color:red">Delete Address</a></p>');
    AddressFormP.append(removeForm);

    removeForm.on('click', function(e){
        e.preventDefault();

        AddressFormP.remove();
    });
}

function handleAcData(collectionHolder,newLinkP)
{
    // Get the div that holds the collection of addresses
    collectionHolder = $('div#addressList');

    // add the "add address" anchor
    collectionHolder.append(newLinkP);

    // add a delete link to all of the existing media form elements
    collectionHolder.find('div#one-address').each(function(){
        addAddressDeleteLink($(this))
    });

    // Count the current form inputs
    // use that as the new index when inserting a new item
    collectionHolder.data('index', collectionHolder.find(':input').length);

    return collectionHolder;
}

// ADD FAMILY MEMBER

function addFmemberForm(familyCollectionHolder, newFamilyLinkP){
    // Get the data prototype
    var prototype = familyCollectionHolder.data('prototype');

    // get the new index
    var index = familyCollectionHolder.data('index');

    // Replace '__name__' in the prototype's HTML
    //instead be a number based on how many items we have
    var newForm = prototype.replace(/__name__/g, index);

    // Increase the index with one for the new item
    familyCollectionHolder.data('index', index+1);

    //Display the form in the page nan li, before the "add address" link
    var newFormP = $('<div class="one-fmember"></div>').append(newForm);
    newFamilyLinkP.before(newFormP);
    addFMemberDeleteLink(newFormP);
}

function addFMemberDeleteLink(fmemberFormP)
{
    var removeFormP = $('<p class="centered"><a href="#" style="color:red">Delete member</a></p>');
    fmemberFormP.append(removeFormP);
    removeFormP.on('click', function(e){
        e.preventDefault();
        fmemberFormP.remove();
    })
}

function handleFcData(familyCollectionHolder,newFamilyLinkP)
{
    // Get the div that holds the collection of addresses
    familyCollectionHolder = $('div#familyMembersList');
    // add a delete link to all of the existensing forms
    familyCollectionHolder.find('div.one-fmember').each(function(){
        addFMemberDeleteLink($(this));
    });
    // add the "add address" anchor
    familyCollectionHolder.append(newFamilyLinkP);
    // Count the current form inputs
    // use that as the new index when inserting a new item
    familyCollectionHolder.data('index', familyCollectionHolder.find(':input').length);

    return familyCollectionHolder;
}

/* ADD MEDIA */

function addMediaForm(collectionHolder, newLinkP2){
    // Get the data prototype
    var prototype = collectionHolder.data('prototype');

    // get the new index
    var index = collectionHolder.data('index');

    // Replace '__name__' in the prototype's HTML
    //instead be a number based on how many items we have
    var newForm = prototype.replace(/__name__/g, index);

    // Increase the index with one for the new item
    collectionHolder.data('index', index+1);

    //Display the form in the page nan li, before the "add address" link
    var newFormP = $('<div class="one-media"></div>').append(newForm);
    newLinkP2.before(newFormP);
    addMediaDeleteLink(newFormP);
}

function addMediaDeleteLink(mediaFormP)
{
    var removeForm = $('<p class="centered"><a href="#" style="color:red">Delete Media</a></p>');
    mediaFormP.append(removeForm);

    removeForm.on('click', function(e){
        e.preventDefault();

        mediaFormP.remove();
    });
}

function handleMcData(collectionHolder2,newLinkP2)
{
    // Get the div that holds the collection of addresses
    collectionHolder2 = $('div#mediasList');

    // add the "add address" anchor
    collectionHolder2.append(newLinkP2);

    // add a delete link to all of the existing media form elements
    collectionHolder2.find('div#one-media').each(function(){
        addMediaDeleteLink($(this))
    });

    // Count the current form inputs
    // use that as the new index when inserting a new item
    collectionHolder2.data('index', collectionHolder2.find(':input').length);

    return collectionHolder2;
}

var familyCollectionHolder;

// Set up an "add address" link
var addFMemberLink = $('<a href="#" class="add_fmember_link">Add family member</a>');
var newFamilyLinkP = $('<p class="centered"></p>').append(addFMemberLink);

jQuery(document).ready(function(){

    familyCollectionHolder = handleFcData(familyCollectionHolder, newFamilyLinkP);

    addFMemberLink.on('click',function(e)
    {
        // Prevent the link from creating a "#" on the URL
        e.preventDefault();
        // add a new address form
        addFmemberForm(familyCollectionHolder, newFamilyLinkP);

        var collectionHolder2;
        // Set up an "add address" link
        var addMediaLink = $('<a href="#" class="add_media_link">Add Contact mean</a>');
        var newLinkP2 = $('<p class="centered"></p>').append(addMediaLink);
        collectionHolder2 = handleMcData(collectionHolder2, newLinkP2);
        addMediaLink.on('click', function(e)
        {
            // Prevent the link from creating a "#" on the URL
            e.preventDefault();
            // add a new address form
            addMediaForm(collectionHolder2, newLinkP2);
        });

        var collectionHolder;

        // Set up an "add address" link
        var addAddressLink = $('<a href="#" class="add_address_link">Add address</a>');
        var newLinkP = $('<p class="centered"></p>').append(addAddressLink);
        collectionHolder = handleAcData(collectionHolder, newLinkP);
        addAddressLink.on('click', function(e)
        {
            // Prevent the link from creating a "#" on the URL
            e.preventDefault();
            // add a new address form
            addAddressForm(collectionHolder, newLinkP);
        })
    })
});

EDIT 2 : The previous solution gives visually the right result but the index is not increasing for address and for media... I've tried to make it with event propagation like :

jQuery(document).ready(function(){

familyCollectionHolder = handleFcData(familyCollectionHolder, newFamilyLinkP);



  addFMemberLink.on('click',function(e)
    {
        // Prevent the link from creating a "#" on the URL
        e.preventDefault();

        // add a new address form
        addFmemberForm(familyCollectionHolder, newFamilyLinkP);

    });
});
$(document).on('click',addAddressLink,function(e){
    e.preventDefault();
    collectionHolder = handleAcData(collectionHolder, newLinkP);
    addAddressForm(collectionHolder, newLinkP);
});

But the result is the same, I can do the job, but the index of address and media is not increasing so when I submit the form I have only the last address and the last media of the list....

Grechka Vassili
  • 753
  • 1
  • 12
  • 26

1 Answers1

2

As described in the jQuery documentation for .on(), you can set up a handler on $(document) and pass the actual target selector as the second parameter:

$(document).on("click", "p.centered", function() {
  // event handler code here
});

You only have to do that once, and then all clicks on <p class=centered> elements will be handled by that code.

Pointy
  • 371,531
  • 55
  • 528
  • 584
  • Ok, I've tried your solution but the index of address and media is not increasing and as I understand the collectionHolder's of address and media must be internal of addAddress ? – Grechka Vassili Feb 21 '17 at 10:08
  • @GrechkaVassili it looks like your code never updates the "index" data. You have to put the incremented index value back so that the next time you'll get a larger number. – Pointy Feb 21 '17 at 13:29