CodeCharge Studio
search Register Login  

Web Reporting

Visually create Web Reports in PHP, ASP, .NET, Java, Perl and ColdFusion.
CodeCharge.com

YesSoftware Forums -> CodeCharge Studio -> PHP

 [How To] Autofill on editable grid

Print topic Send  topic

Author Message
rew-NZ

Posts: 21
Posted: 05/31/2008, 1:12 AM

Hi all,
I tried using auto fill on an editable grid which is not currently possible right out of the box using the tools>Builders>Feature Builder.

The setup
I had an editable grid that had one list box for a field so that the user could edit a field based on known values from another table. As you would expect a change in the selected value would then need to update other fields in the same row of the editable grid that reflect data relating to the selection.

For example:
  
<ComponentId>    <Name>    <Qty>    <Supplier Name>    <Supplier Phone Number>  
  
The Supplier Name is actually a list of suppliers with the supplierId as the value and the Supplier Name as the text.   
So on changing the supplier the Supplier Phone Number would need to change.  

The Problem:
The Autofill AJAX feature that can be setup using the feature builder in the tool kit isn't designed to work within editable grids (yet). The problem is that editable grid controls, like list boxes and text boxes, are uniquely identified by appending the row number to the end of the ID value for the control. So the ID for a field control might be ID="SupplierName" but for each actual control in each row it is ID="SupplierName_[row number]". The feature builder doesn't accommodate the extra content in the control ID that identifies which row the control is in.

My Solution:
1) I used the feature builder to create the Autofill to auto generate the code for the AJAX call and the service required for the autofill in my grid and pointed it to the required fields as I went through the wizard.

2) Once setup I went into the HTML view for the page and found the newly generated code, which will look something like:

  
function vwjobcomponentsDefaultSupplierIdPTAutoFill1_start(sender) {  
    new Ajax.Request("services/Components_SupplierId_PTAutoFill1.php?keyword=" + $("componentsSupplierId").value, {  
        method: "get",  
        requestHeaders: ['If-Modified-Since', new Date(0)],  
        onSuccess: function(transport) {  
            var valuesRow = eval(transport.responseText)[0];  
            getSameLevelCtl("componentsSupplierPhoneNumber", sender).value = valuesRow["SupplierPhoneNumber"];  
        },   
        onFailure: function(transport) {  
            alert(transport.responseText);  
        }  
    });  
}  
Some things that help to know:
-The 'sender' is the row listbox control and it's ID value holds the row number that is needed.
-The dependant control/s use the same row number

3) Edit the generated code to firstly extract the row number from the sender.id and then add it to the control id's to match the controls in the row being updated. It needs to be added to the control ID supplying the search value and the controls that are being updated with the AJAX response data. The result should look something like this:

  
function vwjobcomponentsDefaultSupplierIdPTAutoFill1_start(sender) {  
     //get the row identifier which is the number after the last '_'  
    var id_index = sender.id.lastIndexOf("_")+1;    
    var row_id = sender.id.slice(id_index);  
  
    //_".row_id added to all control id's  
    new Ajax.Request("services/Components_SupplierId_PTAutoFill1.php?keyword=" + $("componentsSupplierId_"+row_id).value, {  
        method: "get",  
        requestHeaders: ['If-Modified-Since', new Date(0)],  
        onSuccess: function(transport) {  
            var valuesRow = eval(transport.responseText)[0];  
            getSameLevelCtl("componentsSupplierPhoneNumber_"+row_id, sender).value = valuesRow["SupplierPhoneNumber"];  
        },   
        onFailure: function(transport) {  
            alert(transport.responseText);  
        }  
    });  
}  

Save the file, publish the page and you should find that the auto fill is now working on any row in the editable grid.

Side Note:
If you try and do the same thing with a returning field called 'Name' you might find the service fails. The reason is 'Name' is a key word and for some reason, when I did it, the service used "name"={name} in the returning grid generated which you will find other wizards usually give you "name"={name1} to avoid the conflict. To fix the problem open the service, named in the function for the autofill, found under the Services folder in the files list and change {Name} to {Name1} publish the service and it will burst into life.

Rew
View profile  Send private message
rew-NZ

Posts: 21
Posted: 05/31/2008, 1:14 AM

This approach should also work for dependent lists in an editable grid.

Rew
View profile  Send private message
ColinA

Posts: 9
Posted: 06/24/2008, 7:25 PM

Thanks for a useful post with in-depth info.

I have tried using this method but get a run time error message "Value is null or not an object" referencing the line number for the text starting "new Ajax Request". If I replace the Grid with a Record the Autofill works OK.

In the following, the table is "doclines" and the editable grid has only two columns "entity" and "description". On changing the "entity" value the description should be defaulted from the table "entitydefaults". Originally I had a table name "doc_lines" and changed it in case that caused a problem.

//PTAutoFill1 Loading @10-66228FE3
function doclinesentityPTAutoFill1_start(sender) {
var row_id = sender.id.split("_")[1];
new Ajax.Request("services/testnounderbars_doclines_entity_PTAutoFill1.php?keyword=" + $("doclinesentity_".row_id).value, {
method: "get",
requestHeaders: ['If-Modified-Since', new Date(0)],
onSuccess: function(transport) {
var valuesRow = eval(transport.responseText)[0];
getSameLevelCtl("doclinesdescription_".row_id, sender).value = valuesRow["description"];
},
onFailure: function(transport) {
alert(transport.responseText);
}
});
}
//End PTAutoFill1 Loading


_________________
Col
View profile  Send private message
rew-NZ

Posts: 21
Posted: 06/24/2008, 8:36 PM

Hi Colin,

The problem with the error is that it might be from anywhere in the AJAX request parameters or when the call back function fires so you need to identify what has a null value or is not an object and when.

I would check your element id "doclinesdescription_" and "doclinesentity_" is correct against your html element id for the input fields in your grid first. Typo's are always a first step.

Do you use FireFox with the Firebug plug-in for debugging your pages HTML/DOM/Javascript, AJAX calls and http requests? You can load the page, view the Javascript function in Firebug and place a stop at the beginning of the AJAX function then trigger it in your grid and step through your script code to see what is happening. You can also inspect elements on the page to check the id attributes and view the http requests, if one gets to fire off to the service, enabling you to see both the POST and GET values sent and received. It might be you are getting and error back from the service rather than a value for valuesRow["description"], just as an example. I would recommend debugging with Firebug and letting us know the result.

else
You can modify your code to provide a little debug or pull out an offending element call, would look something like this:

  
function doclinesentityPTAutoFill1_start(sender) {  
  
alert(sender.id);   
var row_id = sender.id.split("_")[1];  
  
var row_element_value = $("doclinesentity_"+row_id).value;  
  
new Ajax.Request("services/testnounderbars_doclines_entity_PTAutoFill1.php?keyword=" +row_element_value , {  
method: "get",  
requestHeaders: ['If-Modified-Since', new Date(0)],  
onSuccess: function(transport) {  
var valuesRow = eval(transport.responseText)[0];  
getSameLevelCtl("doclinesdescription_"+row_id, sender).value = valuesRow["description"];  
},  
onFailure: function(transport) {  
alert(transport.responseText);  
}  
});  
}  

Rew
View profile  Send private message
ColinA

Posts: 9
Posted: 06/25/2008, 4:36 AM

Thanks for a prompt and informative response.

I do not have FireFox and Firbug but will evaluate installing them.

alert(sender.id); displayed "doclinesentity_4" correctly for the 4th row and also for the other rows.

alert(sender.id.split("_")[1]); displayed the row number correctly for all rows.

However, the error message is now:
'value' is null or not an object"
The reference for this error message is the script line:
var row_element_value = $("doclinesentity_".row_id).value;

It works OK if I replace "row_id" with a specific row number (row 4 in the following) and "alert(row_element_value);" displays the correct value:

function doclinesentityPTAutoFill1_start(sender) {

alert(sender.id);

var row_id = (sender.id.split("_")[1]);
alert(row_id);

var row_element_value = $("doclinesentity_4").value;
alert(row_element_value)

new Ajax.Request("services/testnounderbars_doclines_entity_PTAutoFill1.php?keyword=" + row_element_value, {
method: "get",
requestHeaders: ['If-Modified-Since', new Date(0)],
onSuccess: function(transport) {
var valuesRow = eval(transport.responseText)[0];
getSameLevelCtl("doclinesdescription_".row_id, sender).value = valuesRow["description"];
},
onFailure: function(transport) {
alert(transport.responseText);
}
});
}


_________________
Col
View profile  Send private message
ColinA

Posts: 9
Posted: 06/25/2008, 8:24 PM

Rew I have now fixed the problem by replacing .row_id with + row_id

Your help has been greatly appreciated!
:-)
_________________
Col
View profile  Send private message
rew-NZ

Posts: 21
Posted: 06/25/2008, 9:48 PM

lol that will do it :-) I will update the original post.

Must have been PHP coding at the time and forgot the JavaScript syntax. Didn't think to check for my own typos Sorry.
View profile  Send private message
rew-NZ

Posts: 21
Posted: 06/26/2008, 2:45 PM

AutoComplete

On a side note I also got Autocomplete to work (sort of) on an editable grid.
I only get it working on the last add record row and it only worked if there were no errors displayed for any row so it definitely needed some more work but it did work.

The one autofill function is created when the page loads and is bound to one field. I tried to get the multiple rows thing working but with not a lot of joy. I ended up having to find the second to last row of the grid which is the add new record row and attach it to the field I wanted in that row. As I said it worked but if there was an error result from a submission then the row number didn't match the pre-made autofill element id (I think, ran out of time to look into it further) and it returned a script error.

I also tried playing around with the binding to get it creating when there was a keypress or got focus but that didn't seem to work either. If anyone is interested in working together on figuring it out let me know and I will start another post with the detail I do have so far.
View profile  Send private message
ColinA

Posts: 9
Posted: 06/26/2008, 7:47 PM

Rew yes I'm interested in AutoComplete on an editable grid with multiple data entry rows.
_________________
Col
View profile  Send private message
FunkDaddy

Posts: 10
Posted: 04/01/2009, 10:11 PM

Got it to work with a MINOR "modification"....

First of all thanks to rew-NZ for posting this incredibly valuable code for Autofilling editable grids!!!

I copied and pasted your code (and thanks for updating the original post to include the "+row_id"), however, I couldn't get it to work... I kept getting an error message form my browser (one of those unobtrusive jv erros on bottom of browser status bar that doesn't immediately jump out at you). The message was "Object Required" line # 60"... which was the line code where I staretd the "new Ajax.Request etc..."

Anyhow, after a few tries I noticed that if I removed the last } shown in the last line of your code (1st posting on this chart thread) no more error messages.
View profile  Send private message
rew-NZ

Posts: 21
Posted: 04/01/2009, 11:12 PM

interesting! I dropped both code snippets into notepad++ and found that there was a " missing in
valuesRow["SupplierPhoneNumber]
. I suspect that will not help so you may find that removing the } is not actually the fix you need. I will change the code above, can you retry it and let us know how you get on. (grr typo's!)
Cheers,

Rew
View profile  Send private message
FunkDaddy

Posts: 10
Posted: 04/02/2009, 3:04 PM

Humm...OK I don't know what the hell I am doing. rew-NZ you are right, my last posting was not correct (I just tested it again) and not working.

Anyhow, I did try your code (I added back the "}" I had taken out) and I still get a error on the page. I used Firebox deubbger and I get this:

$("componentsSupplierId_"+row_id) is null

Not sure what to do! Thanks in advance for ay help! Best

View profile  Send private message
FunkDaddy

Posts: 10
Posted: 04/02/2009, 7:28 PM

I am a moron!!!

Hopefully this entry will help other newbies like me... so I figured out what my problem was:

The field name I was seeking to lookup contained an underscore in the name... this caused the code posted on this thread to pick-up on that underscore and treat it as the identifier for the row_id number... thus, all I had to do was change this:

var row_id = sender.id.split("_")[1];

To this:

var row_id = sender.id.split("_")[2];

That simply tells it to pick-up on the second underscore. Alternatively, you can also simply not use field names with underscores! :-)

Hope this helps someone in the future.
View profile  Send private message
rew-NZ

Posts: 21
Posted: 04/02/2009, 7:57 PM

That will do it, but what if you have multiple _'s in the name?
I suspect that var row_id = sender.id.split("_")[n]; is not the best strategy.
The other way to go would be to find the first _ from the right and get the remaining sub string from that position. That way you could have as many _'s as you like without breaking it because the last _ is always the ID separator.
var id_index = sender.id.lastIndexOf("_")+1;  
var row_id = sender.id.slice(id_index);

Another way of doing the same thing would be to split it, find the max count of the split and us that -1.
var id_split = sender.id.split("_");  
var row_id = sender.id.split("_")[id_split.length-1];

This is just off the top of my head so you would need to check to see if +1 was required for the first example. I like the first option more because it specifies what you are looking for and where more directly.
Cheers,

Rew
View profile  Send private message

Add new topic Subscribe to topic   


These are Community Forums for users to exchange information.
If you would like to obtain technical product help please visit http://support.yessoftware.com.

Web Database

Join thousands of Web developers who build Web applications with minimal coding.
CodeCharge.com

Home   |    Search   |    Members   |    Register   |    Login


Powered by UltraApps Forum created with CodeCharge Studio
Copyright © 2003-2004 by UltraApps.com  and YesSoftware, Inc.