Welcome to the nuBuilder Forums!

Register and log in to access exclusive forums and content available only to registered users.

Dynamically add lookup elements

Questions related to customising nuBuilder Forte with JavaScript or PHP.
stevedb
Posts: 21
Joined: Tue Oct 16, 2018 12:21 am

Dynamically add lookup elements

Unread post by stevedb »

Hi,
I would like to place lookups on a form dynamically :shock:
I intend to then collect all the data from the lookups and process them with my own JavaScript and PHP.

I've placed a lookup hidden on the form as a base and I create copies of that and positioned them where I want on the form; using cloneNode and appendChild after altering Id's and positions.

My first three attempts at this have failed ...
1) When I use the lookup on my cloned lookup the resulting record selection ends up in the base lookup.
2) I tried creating a new 'data-nu-object-id' with nuID() for this but that causes a JavaScript error (Uncaught Error: Syntax error, unrecognized expression: #).
3) I also tried keeping the same but giving my clone a 'data-nu-prefix' attribute, but still causes a JavaScript error (Uncaught Error: Syntax error, unrecognized expression: #).

I guess the problem is that when the lookup browse returns it uses the lookup's attributes from the form's object in the database and the lookups I've created are not in the there.
I'm also guessing the solution would be somehow updating the forms properties when I dynamically add the lookup, but I'm not sure how to proceed with that.
I know what I'm doing is not 'ideal' but any guidance on how I might achieve this would be greatly appreciated.
Thanks!
Steve
kev1n
nuBuilder Team
Posts: 4416
Joined: Sun Oct 14, 2018 6:43 pm
Has thanked: 74 times
Been thanked: 472 times
Contact:

Re: Dynamically add lookup elements

Unread post by kev1n »

Hi,

Could you use the code you use to clone the lookup object? Then I can do some experimentation.
stevedb
Posts: 21
Joined: Tue Oct 16, 2018 12:21 am

Re: Dynamically add lookup elements

Unread post by stevedb »

kev1n wrote:Hi,

Could you use the code you use to clone the lookup object? Then I can do some experimentation.
No problem:

Code: Select all

// Create a copy of a lookup widget already on the form (with id baseIdName) and
// add it to the form appended to containerIdName at a new x,y location with a 
// new id newIdName
// containerIdName  = I think this is always 'nuRECORD'
// baseIdName       = ID of lookup we're copying
// newIdName        = ID of our new lookup
// prefix           = prefix name for experimenting with data-nu-prefix
// x,y              = New location
function cloneLookUp(containerIdName, baseIdName, newIdName, prefix, x , y) {
    var i,z;
    var elem;
    var this_nuID = nuID();
    var baseElement               = document.getElementById(baseIdName);
    var baseElement_label         = document.getElementById('label_' + baseIdName);
    var baseElement_idcode        = document.getElementById(baseIdName + 'code');
    var baseElement_idbutton      = document.getElementById(baseIdName + 'button');
    var baseElement_iddescription = document.getElementById(baseIdName + 'description');
    
    var newElement               = baseElement.cloneNode(true);
    var newElement_label         = baseElement_label.cloneNode(true);
    var newElement_idcode        = baseElement_idcode.cloneNode(true);
    var newElement_idbutton      = baseElement_idbutton.cloneNode(true);
    var newElement_iddescription = baseElement_iddescription.cloneNode(true);
    
    var elems = [newElement, newElement_label, newElement_idcode, newElement_idbutton, newElement_iddescription];
    var xAdj  = [         0,             -109,                 0,                  76,                       95];
    // Update id's & positions
    for(z = 0; z < elems.length; z++) {
        elem = elems[z];
        elem.style.left = (x + xAdj[z]) + 'px';
        elem.style.top = y + 'px';
        
        // Experiment to change the data-nu-object-id
        // elem.setAttribute('data-nu-object-id', this_nuID);
        
        // Experiment to use data-nu-prefix property
        // elem.setAttribute('data-nu-prefix', prefix);
        for(i = 0; i < elem.attributes.length; i++) {
            var attrib = elem.attributes[i];
            if (attrib.specified) {
                attrib.value = attrib.value.replace(baseIdName, newIdName);
            }
        }
    }
    
    newElement_label.style.visibility = 'visible';
    newElement_idcode.style.visibility = 'visible';
    newElement_idbutton.style.visibility = 'visible';
    newElement_iddescription.style.visibility = 'visible';
    
    // Put the new elements in the form
    for(z = 0; z < elems.length; z++) {
        elem = elems[z];
        document.getElementById(containerIdName).appendChild(elem);
    }
    
}
admin
Site Admin
Posts: 2822
Joined: Mon Jun 15, 2009 2:23 am
Been thanked: 29 times

Re: Dynamically add lookup elements

Unread post by admin »

stevedb,

You'll need to update the data-nu-target attribute on 2 HTML objects.
Untitled.png
Steven
You do not have the required permissions to view the files attached to this post.
stevedb
Posts: 21
Joined: Tue Oct 16, 2018 12:21 am

Re: Dynamically add lookup elements

Unread post by stevedb »

Thanks for the tip Steven but I'm already doing this by looping through all attributes and renaming them from the base name to the new name:

Code: Select all

            attrib.value = attrib.value.replace(baseIdName, newIdName);
I'm also setting data-nu-prefix to my prefix.
I call my cloneLookUp(containerIdName, baseIdName, newIdName, prefix, x , y) in this way
cloneLookUp('nuRECORD', 'myPrefix_000baseAssyCode_id', 'myPrefix_001baseAssyCode_id', 'myPrefix_001', 150, 230);
I've verified it is actually changing the attributes as expected.
I think the problem I'm facing with doing it this way is I want to dynamically add the lookups to the main form, not a subform.
Steve
kev1n
nuBuilder Team
Posts: 4416
Joined: Sun Oct 14, 2018 6:43 pm
Has thanked: 74 times
Been thanked: 472 times
Contact:

Re: Dynamically add lookup elements

Unread post by kev1n »

If I'm not mistaken, data-nu-object-id (object_id) is somehow used to determine the target field.

In nuajax.js, nuAjax() is called with call_type = 'getlookupid'

In nuform.php, nuGetAllLookupValues() is called
https://github.com/steven-copley/nubuil ... m.php#L487

An finally nuPopulateLookup(data, id) to populate the picked value.
https://github.com/steven-copley/nubuil ... ax.js#L540

If you create elements on the fly, the object_id is not in the table an hence, the lookup cannot be populated. (Again, If I'm not mistaken... Steven can confirm and explain better.)
admin
Site Admin
Posts: 2822
Joined: Mon Jun 15, 2009 2:23 am
Been thanked: 29 times

Re: Dynamically add lookup elements

Unread post by admin »

stevedb,

kev1n's correct, the data-nu-object-id needs to be a valid id of a Lookup Object that has been already created.

It lets nuBuilder know what to populate Code and Description with.

So don't change data-nu-object-id, but make the data-nu-target_id the same as the hidden id field (which is the same as the Lookup Object's id).
lid.png

Steven
You do not have the required permissions to view the files attached to this post.
stevedb
Posts: 21
Joined: Tue Oct 16, 2018 12:21 am

Re: Dynamically add lookup elements

Unread post by stevedb »

OK, on closer inspection of nuGetLookupId and nuPopulateLookup some clarity is forming; thank you very much for your help in getting me to this point!

Now my template lookup's id contains no prefix and the instance of it I create has the same id which includes a prefix. I do find that setting my instance's data-nu-target to the template's id as suggested makes it not work; which makes sense since nuPopulateLookup uses the target to get the prefix which only exists in my instance; not the template.

Anyhow; it now kind of works ... but,
I get a 'Uncaught Error: Syntax error' I would like to clean up. The error comes from the fact that my instance has a prefix so in nuGetLookupId the code drops into nuAddSubformRow and the sfid ends up being empty.
I can add a return if sfid is empty in nuAddSubformRow; but I don't know if that is a good solution, and maybe I'm doing something else wrong?
For completeness here is the now cleaned up code for creating another lookup instance (not form or db object) of a template lookup (a real form object in the db).

Code: Select all

//Called like :
createNewLookUpInstance('nuRECORD', 'hiddenAssyCode_id', 'myPrefix_000', 'My Label Text', 150, 230);

// Create a new instance of a lookup widget already on the form (the template lookup).
// Then append it to the form at a new x,y location.
// 
// formContainerIdName  = I think this is always 'nuRECORD'
// templateId           = ID of template lookup which is already a form object in the DB
// prefix               = prefix name for the data-nu-prefix attribute, also gets added
//                        to templateId to create the ID for the  new instance
// instancelabel        = Label text for this instance of the template
// x,y                  = New location coordinates
function createNewLookUpInstance(formContainerId, templateId, prefix, instancelabel, x , y) {
    // Create clones of all the templates lookup elements
    var newInstance               = document.getElementById(templateId).cloneNode(true);
    var newInstance_label         = document.getElementById('label_' + templateId).cloneNode(true);
    var newInstance_idcode        = document.getElementById(templateId + 'code').cloneNode(true);
    var newInstance_idbutton      = document.getElementById(templateId + 'button').cloneNode(true);
    var newInstance_iddescription = document.getElementById(templateId + 'description').cloneNode(true);
    // Prepare for looping through elements
    var elems = [newInstance, newInstance_label, newInstance_idcode, newInstance_idbutton, newInstance_iddescription];
    var xAdj  = [         0,               -109,                  0,                   76,                     95];
    // Update id's & positions
    var elem   = {}; // Current element in the loop
    var attrib = {}; // Current element attribute in the loop
    for(var ielems = 0; ielems < elems.length; ielems++) {
        elem = elems[ielems];
        elem.style.left = (x + xAdj[ielems]) + 'px';
        elem.style.top = y + 'px';
        // Make label, code and description visiible; we assume template is not
        if(ielems > 0) {
            elem.style.visibility = 'visible';
            elem.style.display = '';
        }
        // Update the label text
        if(ielems == 1) {elem.innerText = instancelabel;}
        // Add data-nu-prefix property
        if(prefix != '') {elem.setAttribute('data-nu-prefix', prefix);}
        // Change any reference to the template ID in the attributes to the newInstance ID
        for(var iattribs = 0; iattribs < elem.attributes.length; iattribs++) {
            attrib = elem.attributes[iattribs];
            if (attrib.specified) {
                attrib.value = attrib.value.replace(templateId, prefix + templateId);
            }
        }

    }
    // Put the new elements in the form
    for(ielems = 0; ielems < elems.length; ielems++) {
        elem = elems[ielems];
        document.getElementById(formContainerId).appendChild(elem);
    }
}
admin
Site Admin
Posts: 2822
Joined: Mon Jun 15, 2009 2:23 am
Been thanked: 29 times

Re: Dynamically add lookup elements

Unread post by admin »

stevedb,

You seem to be trying to reinvent the wheel.

Adding dynamic Lookups is automatically done when you put a Lookup in a Subform.

Can you explain what you are trying to achieve and how you hope to save it all in the database?


Steven
stevedb
Posts: 21
Joined: Tue Oct 16, 2018 12:21 am

Re: Dynamically add lookup elements

Unread post by stevedb »

What I'm trying to achieve is best described as a configurator.
This is essentially a configurator for items and options on a product's build where if one type of item is fitted there are a multitude of additional child options that then become available; some of which may have child options too but there is no way of knowing until the option is chosen.
A simple analogy would be like a car configurator where you would only show the availability of the satnav option if the entertainment system was one of the types that supported it.
But this happens to be a modular frame like a server rack.

I did look at using a subform for this but I worried about how to handle the situation when you might be 40 rows into data entry then go back to row 2 and change the entry to something that has more children I would have to shift all the subforms div's down and possibly rename all the prefixes. Also I want to display empty options, so some pre-processing is required so I do not add empty records.
I have to re-position the lookups in the non-subform way of doing it but in this case I do not care about the prefix numbering.
I have noticed other 'funnies' with trying to create new instances of a lookup on the form (they disappear when I click the tab), so if you understand what I'm trying to do and think subforms are the way to go to avoid unforeseen side effects I'll persevere with that but I have a few questions:
-Does anything care about the order of the prefix's used in the subform records or if there are gaps?
-Are a Subforms records limited to 1000 entries?
-I want to show empty options, so based on the type of item in record one I may want to add 4 empty subform rows. Would the best way of handling this be to manage the delete option with some javascript; automatically mark for delete until that option is set to something?
Many thanks,
Steve
Post Reply