Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using only a controller in FW1 without a view

I have an Ajax request that sends some data to a page and expects back a truthy or falsey value depending on if the data was saved. In my controller I do everything and set the content to a true or false value. I really don't want to create a view just to output 1 variable, so I was wondering if there was a way that I don't have to use a view and only use the controller to output simple strings.

like image 330
Dave Long Avatar asked Feb 20 '23 15:02

Dave Long


2 Answers

I believe you cannot disable views completely, but there's a pretty simple workaround: you can create one view and use it for many actions.

Let's say we've created the view views/main/ajax.cfm, what could be inside it? Obviously, simplest way is:

<cfoutput>#HTMLEditFormat(rc.response)#</cfoutput>

Personally I like returning JSON, it allows me to have status field, plus data, if needed. This way my view looks like this:

<cfheader name="Content-Type" value="application/json" />
<cfoutput>#SerializeJSON(rc.response)#</cfoutput>

Any way, now in our action we need to do something like this:

// prevent displaying the layout
request.layout = false;

// force special view
variables.fw.setView("main.ajax");

// init response (according to the choice made earlier)
rc.response["status"] = "OK";
rc.response = "";

There's one more gotcha for this. Sometimes you don't want AJAX page to be accessed directly (like opened in browser), or vise-versa -- want to do some debugging when it is.

There's a cool helper isAjax in CFWheels framework, it is easy to port to the FW/1. It could be as simple as adding method like this to controller:

/*
* Check if request is performed via AJAX
*/
private boolean function isAjax() {

    return (cgi.HTTP_X_REQUESTED_WITH EQ "XMLHTTPRequest");

}

Actually, that setup code above is also helper method in my apps:

/*
* Set up for AJAX response
*/
private struct function setAjax() {

    // prevent displaying the layout
    request.layout = false;

    // force special view
    variables.fw.setView("main.ajax");

    local.response["status"] = "OK";

    return local.response;

}

So in my action code whole check looks like this, which is pretty compact and convenient:

if (isAjax()) {
    rc.response = setAjax();
}
else {
    return showNotFound();
}

Hope this helps.

like image 168
Sergey Galashyn Avatar answered Feb 28 '23 05:02

Sergey Galashyn


You can't output directly from a Controller: its job is just to call the Model and pass data to the View, so you'll need a view template to do the outputting.

However, you can avoid having to create a separate view for each controller method by using the framework's setView() method. This allows you to override the convention and apply a single view to multiple controller methods. So you could set up a generic "ajax view" and then use it to output the data from any of your controllers:

views/main/ajax.cfm

<!---Prevent any layouts from being applied--->
<cfset request.layout=false>
<!--- Minimise white space by resetting the output buffer and only returning the following cfoutput --->
<cfcontent type="text/html; charset=utf-8" reset="yes"><cfoutput>#rc.result#</cfoutput>

controller.cfc

function init( fw )
{
variables.fw=arguments.fw;
return this;
}

function getAjaxResponse( rc )
{
    rc.result=1;
    fw.setView( "main.ajax" );
}

function getAnotherAjaxResponse( rc )
{
    rc.result=0;
    fw.setView( "main.ajax" );
}
like image 36
CfSimplicity Avatar answered Feb 28 '23 04:02

CfSimplicity