I have a case where i need to add the Javascript from controller to the Layout where it has already HeadScript();
How to do that from controller?
e.g: $this->view->HeadScript()->appendScript();
This is controller: Both does not apply.
class RouterController extends Zend_Controller_Action
{
public function init()
{
$this->view->HeadScript()->appendFile('/js/test.js')->setIndent(8);
$this->view->HeadScript( Zend_View_Helper_HeadScript::FILE, '/js/test.js' );
}
}
This is the view file: index.phtml
<?//$this->HeadScript()->appendFile('/js/test.js')->setIndent(8);?>
If i uncomment in view it works but not in Controller. I want to apply this from controller how now?
$this->view->headScript()->appendFile('/path/to/file.js');
<?//$this->HeadScript()->appendFile('/js/test.js')->setIndent(8);//Your question ?>
$this->view->headScript()->appendFile('/path/to/file.js');//Alex Howansky's answer
There slightly different. :)
I got this to work from the preDispatch method in a controller, remember you have to pass layout changes before headers are passed.
public function preDispatch() {
parent::preDispatch();
$layout = new Zend_Layout();
$layout->getView()->headScript()->appendScript('/javascript/form.js', 'text/javascript');
}
you still have to have the headScript placeholder in your layout.
$this->view->HeadScript( Zend_View_Helper_HeadScript::FILE, '/path/to/file.js' );
or
$this->view->HeadScript( Zend_View_Helper_HeadScript::SCRIPT, 'js code' );
The same for $this->view->InlineScript().
$headScript = $this->getServiceLocator()->get('viewhelpermanager')->get('headScript');
$headScript->prependFile($this->getSystemBaseUrl()."js/front_end/lib/jQuery/jquery-2.2.3.min.js","text/javascript");
In case if its still useful to someone, you need to include following in layout script file:
<?php echo $this->headScript(); ?>
Reference: https://framework.zend.com/manual/1.11/en/zend.view.helpers.html#zend.view.helpers.initial.headscript
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 a file in my yii first project. my project has a new theme with this path
first_proj\themes\project\views\layouts\main.php
and i want to call a function in it like below
<?php
if($is_project_manager){
?>
<div class="each-pop-el" style="cursor:pointer" ng-click="showAllMemberTask()">show tasks</div>
<?php } ?>
and have function in
first_proj\protected\controllers\project.php
this is
public function actionIsProjectmanager(){
$project_manager = false;
$crt = new CDbCriteria;
$crt->condition = 'user_id=:uid and role=1';
$crt->params = array('uid'=>Yii::app()->user->id);
$project_manager= projectMember::model()->findAll($crt);
// $model_result = MyModel::model()->test();
$this->render('the url to theme and main.php file', array('is_project_manager' => $project_manager));
}
how can i reach to that main.php file ? what i must write instead of
the url to theme and main.php file in my function ?
You set the controllers layout to the file. So it would look like this:
$this->layout = 'main';
Layouts must be rendered with a view file as well though.
$this->render('index', array('is_project_manager' => $project_manager));
Then place an index.php file in your views/project folder with the actions content.
This assumes you've setup your config to have the theme as project
First thing you need to know is: No need to pass layout file to the view. When you use render() function, yii automatically add layout to your view. Then, For specifying the layout, you need to use $this->layout = '//layouts/main in your action.
use this in your view
<?php
if($this->isProjectmanager){
?>
<div class="each-pop-el" style="cursor:pointer" ng-click="showAllMemberTask()">show tasks</div>
<?php } ?>
and create a helper function (not an action!) in your controller
public function IsProjectmanager(){
if ($someConditon) {
return true;
}
else {
return false;
}
}
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'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
OK, so I'm trying to teach myself the CakePHP framework, and I'm trying to knock up a simple demo app for myself.
I have the controllers, views and models all set up and working, but I want to do something slightly more than the basic online help shows.
I have a guitars_controller.php file as follows...
<?php
class GuitarsController extends AppController {
var $name = 'Guitars';
function index() {
$this->set('Guitars', $this->Guitar->findAll());
$this->pageTitle = "All Guitars";
}
function view($id = null) {
$this->Guitar->id = $id;
$this->set('guitar', $this->Guitar->read());
// Want to set the title here.
}
}
?>
The 'Guitar' object contains an attribute called 'Name', and I'd like to be able to set that as the pageTitle for the individual page views.
Can anyone point out how I'd do that, please?
NB: I know that there is general disagreement about where in the application to set this kind of data, but to me, it is data related.
These actions are model agnostic so can be put in your app/app_controller.php file
<?php
class AppController extends Controller {
function index() {
$this->set(Inflector::variable($this->name), $this->{$this->modelClass}->findAll());
$this->pageTitle = 'All '.Inflector::humanize($this->name);
}
function view($id = null) {
$data = $this->{$this->modelClass}->findById($id);
$this->set(Inflector::variable($this->modelClass), $data);
$this->pageTitle = $data[$this->modelClass][$this->{$this->modelClass}->displayField];
}
}
?>
Pointing your browser to /guitars will invoke your guitars controller index action, which doesn't exist so the one in AppController (which GuitarsController inherits from) will be run. Same for the view action. This will also work for your DrumsController, KeyboardsController etc etc.
You can set this in the controller:
function view($id = null) {
$guitar = $this->Guitar->read(null, $id);
$this->set('guitar', $guitar);
$this->pageTitle = $guitar['Guitar']['name'];
}
Or in the view:
<? $this->pageTitle = $guitar['Guitar']['name']; ?>
The value set in the view will override any value that may have already been set in the controller.
For security, you must ensure that your layout / view that displays the pageTitle html-encodes this arbitrary data to avoid injection attacks and broken html
<?php echo h( $title_for_layout ); ?>
In response to your own answer about oo paradigm. Its like this :
function view($id) {
$this->Guitar->id = $id;
$this->Guitar->read();
$this->pageTitle = $this->Guitar->data['Guitar']['name'];
$this->set('data', $this->Guitar->data);
}
By the way, you should check if id is set and valid etc, since this is url user input.
As of CakePHP 1.3, setting page title has been changed.
$this->pageTitle = "Title"; //deprecated
$this->set("title_for_layout",Inflector::humanize($this->name)); // new way of setting title
Note: More about Inflector: http://api13.cakephp.org/class/inflector#method-Inflector
$this->pageTitle = $this->Guitar->Name;
It should go in the View though, I don't PHP, or cakePHP, but thats something a view should do, not the controller.
It should go in the controller. See this
"but I want to do something slightly more than the basic online help shows."
Isn't that always the rub? So much documentation is geared towards a bare minimum that it really does not help much. You can complete many of the tutorials available but as soon as you take 1 step off the reservation the confusion sets in. Well, it's either bare minimum or pro developer maximum but rarely hits that sweet spot of ease, clarity and depth.
I'm currently rewriting some Zend Framework documentation for my own use simply so I can smooth out the inconsistencies, clarify glossed over assumptions and get at the core, "best practice" way of understanding it. My mantra: Ease, clarity, depth. Ease, clarity, depth.
Ah, the none-obvious answer is as follows...
$this->pageTitle = $this->viewVars['guitar']['Guitar']['Name'];
I found this by placing the following code in the controller (was a long shot that paid off, to be honest)
echo "<pre>"; print_r($this);echo "</pre>";
Thanks to all those that tried to help.
echo "<pre>"; print_r($this);echo "</pre>";
how about
pr( $this );
OK, I really want to set the page title in the controller instead in the view. So here's what I did:
class CustomersController extends AppController {
var $name = 'Customers';
function beforeFilter() {
parent::beforeFilter();
$this->set('menu',$this->name);
switch ($this->action) {
case 'index':
$this->title = 'List Customer';
break;
case 'view':
$this->title = 'View Customer';
break;
case 'edit':
$this->title = 'Edit Customer';
break;
case 'add':
$this->title = 'Add New Customer';
break;
default:
$title = 'Welcome to '.$name;
break;
}
$this->set('title',$this->title);
}
The trick is that you can't set $this->title inside any action, it won't work. It seems to me that the web page reaches action after rendering, however you can do it in beforeFilter.