Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS and ColdFusion CFCs

I'm trying to pick up AngularJS with a ColdFusion back end and am running into a few roadblocks. I am modifying their "To Do" app http://angularjs.org/ with the CF Art Gallery database. I'm trying to link a ColdFusion CFC to an Angular app using AJAX.

Below is my artists.cfc:

<cfcomponent>

<cffunction name="getArtists" access="remote" >
    <cfargument name="firstName" default="">
    <cfargument name="lastName" default="">

    <cfquery name="getArtists_sql" datasource="cfartgallery">
        SELECT
            firstname as text,
            lastname as done 
        FROM artists
        WHERE 0=0
    <cfif firstName neq "">
        AND ucase(firstname) like ucase('%#FIRSTNAME#%')
    </cfif>
    <cfif lastName neq "">
        OR ucase(lastname) like ucase('%#LASTNAME#%')       
    </cfif>
    </cfquery>

    <cfreturn getArtists_sql>
</cffunction>

</cfcomponent>

I call the CFC using AngularJS with the following code:

function TodoCtrl($scope, $http) {
    $http.get('cfc/artists.cfc?method=getArtists&returnformat=json').
        success(function (response) {
            $scope.todos = data.DATA;
    }).
        error(function (data) {
            $scope.todos = data;
        });
}

I know that I get a response back. Below is the JSON string Chrome's developer tools returns for me:

{
"COLUMNS":
    ["TEXT","DONE"],
"DATA":[
    ["Aiden","Donolan"],
    ["Austin","Weber"],
    ["Elicia","Kim"],
    ["Jeff","Baclawski"],
    ["Lori","Johnson"],
    ["Maxwell","Wilson"],
    ["Paul","Trani"],
    ["Raquel","Young"],
    ["Viata","Trenton"],
    ["Diane","Demo"],
    ["Anthony","Kunovic"],
    ["Ellery","Buntel"],
    ["Emma","Buntel"],
    ["Taylor Webb","Frazier"],
    ["Mike","Nimer"]
]}

This doesn't look like the notation Angular used in their demo:

[
{text:'learn angular', done:true},
{text:'build an angular app', done:false}
]

Can someone point me to the right direction as to how I can go about getting this to work properly? Ideally, I would like to keep the CFC intact so that in can be reused for a different application so the JSON manipulation would have to be done in the Javascript end.

like image 228
Chester Avatar asked Feb 25 '13 18:02

Chester


People also ask

How are CFCs distributed in ColdFusion?

All CFCs automatically extend the ColdFusion WEB-INF/ cftags /component.cfc component. (The WEB-INF directory is in the cf_root / wwwroot directory on ColdFusion configured with an embedded J2EE server. It is in the cf_root directory when you deploy ColdFusion on a J2EE server.) This CFC is distributed as a zero-length file.

How do I use the super keyword in ColdFusion?

You use the Super keyword only on CFCs that use the Extends attribute to extend another CFC. Unlike ColdFusion scopes, the Super keyword is not used for variables; it is only used for CFC methods, and it is not available on ColdFusion pages that invoke CFCs.

Where is the WEB-INF directory in ColdFusion?

(The WEB-INF directory is in the cf_root / wwwroot directory on ColdFusion configured with an embedded J2EE server. It is in the cf_root directory when you deploy ColdFusion on a J2EE server.) This CFC is distributed as a zero-length file.

Why does ColdFusion search the package directory first for components?

If you place two components in a single directory as a package, and one component refers to the other with only the component name, not a qualified path, ColdFusion always searches the package directory first for the component.


3 Answers

Or you can use this helper function in javascript to get query as (common) key-value objects array.



    function CFQueryParser(data) {
        let items = [];
        Object.keys(data.DATA).forEach((i) => {
            let item = {};
            Object.keys(data.COLUMNS).forEach((j) => {
                item[data.COLUMNS[j]] = data.DATA[i][j];
            });
            items.push(item);
        })
        return items;
    }


like image 45
Oscar Rico Avatar answered Sep 21 '22 18:09

Oscar Rico


By default, Coldfusion uses a different JSON notation than you may be used to. The column names are stored in one array, while the data is stored in another. The solution we implemented involved changing the CFquery to an array. Then JSONEncoding that array.

You will need this function here:

<cffunction name="QueryToArray" access="public" returntype="array" output="false"hint="This turns a query into an array of structures.">
    <cfargument name="Data" type="query" required="yes" />

    <cfscript>
        // Define the local scope.
        var LOCAL = StructNew();

        // Get the column names as an array.
        LOCAL.Columns = ListToArray( ARGUMENTS.Data.ColumnList );

        // Create an array that will hold the query equivalent.
        LOCAL.QueryArray = ArrayNew( 1 );

        // Loop over the query.
        for (LOCAL.RowIndex = 1 ; LOCAL.RowIndex LTE ARGUMENTS.Data.RecordCount ; LOCAL.RowIndex = (LOCAL.RowIndex + 1)){

        // Create a row structure.
        LOCAL.Row = StructNew();

        // Loop over the columns in this row.
        for (LOCAL.ColumnIndex = 1 ; LOCAL.ColumnIndex LTE ArrayLen( LOCAL.Columns ) ; LOCAL.ColumnIndex = (LOCAL.ColumnIndex + 1)){

        // Get a reference to the query column.
        LOCAL.ColumnName = LOCAL.Columns[ LOCAL.ColumnIndex ];

        // Store the query cell value into the struct by key.
        LOCAL.Row[ LOCAL.ColumnName ] = ARGUMENTS.Data[ LOCAL.ColumnName ][ LOCAL.RowIndex ];

        }

        // Add the structure to the query array.
        ArrayAppend( LOCAL.QueryArray, LOCAL.Row );

        }

        // Return the array equivalent.
        return( LOCAL.QueryArray );

    </cfscript>
</cffunction>

And then your return will look like:

 <cfreturn SerializeJson(QueryToArray(getArtists_SQL),true)>

The thing to remember, is that a CFquery object contains other properties like recordcount...and most likely, the JS only wants the data. I don't know if there is a more elegant solution to this, but this is the solution we landed on when we were having a similar problem with JQgrid.

like image 166
Blaise Swanwick Avatar answered Sep 19 '22 18:09

Blaise Swanwick


To go along with the above answer from Blaise. The queryToArray I use looks at the query object's columnList. This is so the case of the column aliases is preserved. Otherwise it will be all caps in your JSON

/**queryToArray
*  utility method to keep the code dry.
*  @hint does exactly what the name says, take a query, makes it an array of stucts
*  @hint columnLabels pass in a list of columnLabels to just return those columns
*/
public array function queryToArray(required query data, any columnLabels=false){
    var columns = listToArray(arguments.data.columnList);
    if(arguments.columnLabels != false){
            columns = listToArray(arguments.columnLabels);
    }

    var queryArray = arrayNew(1);

    for(i=1; i <= arguments.data.RecordCount; i++){

            row = StructNew();
            for (j=1; j <= ArrayLen(columns); j++){
                columnName = columns[j];
        row[columnName] = arguments.data[columnName][i];
            }
            arrayAppend(queryArray, row);
    }
    return(queryArray);
}
like image 43
user7954 Avatar answered Sep 19 '22 18:09

user7954