In order to provide an ajax action I do the following:
public function preDispatch()
{
if ($this->getRequest()->isXmlHttpRequest()) {
Zend_Controller_Action_HelperBroker::removeHelper('viewRenderer');
Zend_Layout::getMvcInstance()->disableLayout();
}
}
but the response comes with the following error:
script 'async/tax.phtml' not found in path (/var/www/app/trunc/application/views/scripts/:./views/scripts/)
Why not using the Ajaxcontext action helper ? http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.contextswitch
// supposedly in your async controller
public function init() {
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('tax', 'html')
}
Then name your view "async/tax.ajax.phtml" and ensure that your ajax call ask for the html format.
That way you can even adapt your code to automatically respond with json, phtml or xml with the same controller/action.
Have you checked whether the file tax.phtml exists in /var/www/app/trunc/application/views/scripts/ .
If exists , then in tax.phtml place echo exit; at the bottom of the file.
Related
It seems like i am not following the MVC design structure.
I'm making an ajax call from my view to a Controller function
Controller
public function actionGetClient()
{
$user = Client::model()->findByAttributes(array('email'=>$_POST['email'], 'password'=>$_POST['pass']));
echo $user->fullname;
}
View (the calling ajax)
CHtml::ajaxLink(
$text = 'get user',
$url = Yii::app()->createUrl('[my controller]/getClient'),
$ajax=array (
'type'=>'POST',
'data' => array('email'=>email, 'pass'=>pass),
'beforeSend' => "function( request )
{
$(\".result\").html(\"fetching...\")
}",
'success'=>"function(data){
$(\".result\").html(\"user is :\"+data)
}
"
));
Is it good to "echo" the $user->fullname inside the controller for the ajax success function to display it? My boss doesn't like it when i print stuff in my controller, how can i approach this
because when i use return instead, the ajax success gets a null value
return $user->fullname;
No,
It's not a good practice.
You need to create a view to use echo.
You can use return $this->renderPartial('VIEW_NAME'); to render a view without Layout.
You should write 'return' instead of 'echo'. 'echo' is not a good practice for ajax response. You don't need to make a new view for just return a name in your case.
public function actionGetClient()
{
$user = Client::model()->findByAttributes(array('email'=>$_POST['email'],'password'=>$_POST['pass']));
return $user->fullname;
}
No. A controller’s supposed to pass its results to a view for rendering.
I would avoid echoing in the controller what we usually do is have a ajax view folder and a json view and render with that so:
public function actionGetClient()
{
$user = Client::model()->findByAttributes(array(
'email'=>$_POST['email'],
'password'=>$_POST['pass']
));
$this->render("json",array("outputData"=>$user));
}
then add this to the controller as well:
public function getViewPath(){
if(Yii::app()->request->isAjaxRequest){
if(($module=$this->getModule())===null)
$module=Yii::app();
return $module->getViewPath().DIRECTORY_SEPARATOR."ajax";
}
return parent::getViewPath();
}
and in the ajax views folder add a json.php file like so
header('Content-Type: application/json');
// output data
echo json_encode($outputData);
please degug the code as I wrote it free hand. You can also set a marker in the controller like $viewPath and set it before the rendering
i have small trouble...
class Controller {
init() {
// initializing...
// render header && footer
$header = (new HeaderAction)->run();
$footer = (new FooterAction)->run();
// redirect to called action, what renders all the content
}
}
What i can detect diff between ->run() and called action?
Answer found in:
AfterRender -> parse Route -> compare action names. If match - echo, if not match - Return.
Yii is SHIT!!!
I will write new class MyAction with method AddData, what can render for me some viewfile. Creating class CAction for this, what can't rendering? Maybe i must create controller? Are you noob, Quang, ha?
Lol, i can't create the header with action. I must create it in Controller. Controller file now is 1200 lines. >_<
class MyAction {
public $data = array();
public function addData($name, $val) {
$this->data[$name] = $val;
}
public function render($file) {
ob_start;
// ... something
return ob_get_clean;
};
}
/// ITS ALL WHAT NEED ALL THE DEVELOPERS>>>>
BEHAVIORS? EVENTS? FILTERS? WIDGETS? MODULES? MAYBE WE NEED "CAMOBAP" AS AUTOCAR?
REASOOOONS????
===
Lol, there is model cannot to render at all. I have products with views as "tr-tr", and i must create controller, create action, create route for rendering funcking 10 SYMBOLS.... Its Rage. About u, Quang.
Russian Bear will kill you.
I have been successfully using XML view files in CakePHP (request the XML output type in headers so CakePHP will use e.g. Orders/xml/create.ctp instead of Order/create.ctp).
However, now i need to add some functionality that requires me to the reformat the XML at the end of most business logic in the controller.
So i tried this in the controller action:
public function createorder() {
$this->autoRender = false; // disable automatic content output
$view = new View($this, false); // setup a new view
{ ... all kinds of controller logic ...}
{ ... usually i would be done here and the XML would be outputted, but the autorender will stop that from happening ... }
{ ... now i want the XML in a string so i can manipulate the xml ... }
$view_output = $view->render('createorder'); // something like this
}
But what this gives me is:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<error>View file "/Users/test/Documents/hosts/mycakeapp/app/View/Orders/createorder.ctp" is missing.</error>
<name>MissingViewException</name>
<code>500</code>
<url>/orders/createorder/</url>
</response>
So i need to tell CakePHP to pickup the xml/createorder.ctp instead of createorder.ctp. How do i do this?
Cheers!
This answers refers to cakephp 2.4
I have been successfully using XML view files in CakePHP (request the XML output
type in headers so CakePHP will use e.g. Orders/xml/create.ctp
instead of Order/create.ctp).
In lib/Cake/View you can see different View files like:
View.php
XmlView.php //This extends View.php
JsonView.php //This extends View.php
So you told cakephp to use the XmlView. When you create a new View you need to use the XmlView instead of View. Or you can create your own custom View and put it inside app/View folder. In your custom View you can set your subdir.
<?php
App::uses('View', 'View');
class CustomView extends View {
public $subDir = 'xml';
public function __construct(Controller $controller = null) {
parent::__construct($controller);
}
public function render($view = null, $layout = null) {
return parent::render($view, $layout);
}
}
So what you need now is to create your custom view $view = new CustomView($this, false);
You can also write in your CustomView functions to handle the data as xml and use it to every action.
Also #Jelle Keizer answer should work. $this->render('/xml/createorder'); points to app/View/xml/createorder. If you need this to point to app/View/Order/xml/create just use $this->render('/Orders/xml/create');.
$this->render('/xml/createorder');
I'm trying to figure out how to use one of my view elements inside of a controller...
I know, I know: "Don't do that!" (99% of the time this is the correct answer)
But I think I actually have a good reason. The action is handling an AJAX request which returns markup. The returned markup is a list which I display everywhere else using an element. So in an effort to keep my code DRY, I think it's appropriate to do this here.
Is this possible?
Easy:
$view = new View($this, false);
$content = $view->element('my-element', $params);
Also:
DON'T DO THAT ANYMORE!!!
Sometimes, you need to render a CakePhp element from a view and inject its content into the page using AJAX the same time. In this case rendering element as a regular view from controller is better than creating a dedicated view that just contains <?php echo $this->element('some_element') ?>, and may be done this way:
<?php
public function ajax_action() {
// set data used in the element
$this->set('data', array('a'=>123, 'b'=>456, 'd'=>678));
// disable layout template
$this->layout = 'ajax';
// render!
$this->render('/Elements/some_element');
}
I know this is an old question and other people have already given basically the same answer, but I want to point out that this approach (provided by Serge S.) ...
<?php
public function ajax_action() {
// set data used in the element
$this->set('data', array('a'=>123, 'b'=>456, 'd'=>678));
// disable layout template
$this->layout = 'ajax';
// render!
$this->render('/Elements/some_element');
}
...is not a hacky workaround, but is in fact the recommended approach from the CakePHP docs for this common and legitimate use case:
If $view starts with ‘/’, it is assumed to be a view or element file
relative to the /app/View folder. This allows direct rendering of
elements, very useful in AJAX calls.
(Again: Credit to Serge S. for the code above)
$this->view = '/Elements/myelement';
You should use a client-side template. You should never return mark-up from a web service or API, just data. Have your JavaScript take the data, and then format it how you wish.
For example:
function getItems() {
$.get('/some/url', function(response) {
if (response.data.length > 0) {
for (var i = 0; i < response.data.length; i++) {
var item = response.data[i];
$('.results').append('<li>' + item.title + '</li>');
}
}
});
};
This is just an example written off the cuff. Obviously you’ll need to write your own implementation.
The way I did any ajax handling in Cake was to have my own AjaxController. Any interaction of ajax-kind goes there, which in-turn uses their own views (and view partials / elements). That way you can keep your code DRY and isolate and propagate all ajax use-cases there.
Example excerpt:
<?php
class AjaxController extends AppController {
/**
* (non-PHPdoc)
* Everything going to this controller should be accessed by Ajax. End of story.
* #see Controller::beforeFilter()
*/
public function beforeFilter() {
parent::beforeFilter();
$this->autoRender = false;
$this->layout = false;
if (!$this->request->is('ajax')) {
$this->redirect('/');
}
}
public function preview() {
if ($this->request->is('ajax')) {
$this->set('data', $this->data);
$this->render('/Elements/ajaxpreview');
}
}
?>
Here's the source: https://github.com/Sobient/dosspirit/blob/master/app/Controller/AjaxController.php
this is a call to a controllers function :
function downloadFile(fn,con)
{
var loadUrl = "/Fast-Docs/index.php/Docs/downloadFile";
alert('hi');
$.post(
loadUrl,
{content: con, filename: fn});
}
controllers function :
public function downloadFile()
{
$this->load->helper('download');
$content=$this->input->post('content');
$fn=$this->input->post('filename');
return force_download($fn,$content);
}
but file is not downloading.
i know the reason why its not working but i dnt know how to fix it. so whats the solution. you need some more info , feel free to ask.
I don't completely understand what you are trying to do. Anyway, there is a fundamental problem in your code.
You are doing an ajax request to the "/Fast-Docs/index.php/Docs/downloadFile" URL, but you are ignoring the response.
My suggestion is: forget about ajax and use a simple link.
Download file
Then in the controller:
public function downloadFile($filename)
{
//Validate file name
if($filename != 'validFileName') die('Invalid file name');
//Set headers
$this->load->helper('download');
$content = file_get_contents('/images/' . $filename);
force_download($filename, $content);
}
If for some reason you can't use a link, you can redirect to the download page (by setting window.location).
If you really need to use ajax, give a look at this.