I'm working with a CakePHP application and jQuery Mobile. In the CakePHP application, RequestHandler is turned on, now, jQuery Mobile makes all of it's requests as ajax requests but requires a full page not just what is in my view but the full layout to.
I need requesthandler and I've tried to set a layout, force a render, turn off autolayout, nothing works, cake only returns the contents of my view.
I'd really love to know what's going on here.
If anyone is interested I found a solution to this, I found out that when you have RequestHandler on and make a Ajax request, it doesn't matter what you do, RequestHandler then decides that your layout is 'ajax' via call backs, this probably applies for all non-html request types, like json and text.
I had to set
$this->RequestHandler->enabled = false;
It really needs to be set in beforeFilter() as well, latter in the call chain and it appears to not work.
So my code ended up as:
class AppController extends Controller {
var $components = array('RequestHandler');
function beforeFilter() {
if ($this->RequestHandler->isMobile()) {
$this->RequestHandler->enabled = false
//set special mobile rules here
}
}
}
I was having the same problem with a CakePHP 1.3 app that is using jQueryMobile to build mobile-friendly views. I'll try to lay it out for future searches.
When I switched on $.mobile.ajaxEnabled = true; for jQM's nice Ajax-based navigation all the linked pages showed undefined instead of the page content. The Ajax nav requires that the linked page have the proper structure, like so:
<div data-role="page">
<div data-role="header">
<h1>Page Title</h1>
</div><!-- /header -->
<div data-role="content">
<p>Page content goes here.</p>
</div><!-- /content -->
<div data-role="footer">
<h4>Page Footer</h4>
</div><!-- /footer -->
</div><!-- /page -->
This markup was coming from two places for my app, though: my default mobile layout had the <html>, <body> and the page and footer divs. Each view had a header and content div.
The problem arose because Cake's RequestHandler wanted to set the layout to ajax for all Ajax requests. It does this somewhere after beforeFilter(), which caused it to ignore a declared layout there (which Luke mentions).
The ajax layout is empty, unlike my default layout--it doesn't have <html> and other markup because it assumes (rightly) that you only want partial markup that will be inserted into a page by Ajax. The jQuery Ajax-based navigation does want to see the full markup though, and when it didn't receive a well-formed page when making the Ajax request it had no page to display.
So the question became, "How do I make RequestHandler use my default mobile layout for mobile page requests?" I wasn't satisfied with Luke's solution above of disabling RequestHandler completely for mobile. Luckily I found a post from May '11 with the same problem and a better solution:
Finally sorted it! I was checking to see whether a mobile device was
requesting the page using $this->RequestHandler->isMobile(), but had
placed it in the beforeFilter() function. Moving this to the
beforeRender() function in the app_controller.php file fixed the
problem.
http://cakephp.1045679.n5.nabble.com/Jquery-Mobile-and-CakePHP-1-3-td4422871.html
So my code ended up something like this in AppController:
function beforeRender() {
if ($this->RequestHandler->isMobile()) {
$this->layout = 'm_default';
}
}
I hope that helps someone out there.
Just set $this->layout = 'default'; in your controller, and it will use the default layout.
Or maybe you could make a header and footer element to put in your ajax and default layouts.
I was new to CakePHP and started with Version 2 several weeks ago.
So far I also keep the beforeFilter untouched to identifier isMobile() and finally use mobile-views within a Themed-Folder. Therefore I dont use subfolders for mobile-views within the default desktop-views. After adding this->layout in the condition it seems that I got rid off the undefined which appeared only via some actions links.
public function beforeRender() {
if($this->RequestHandler->isMobile()) {
$this->theme = 'Mobile';
$this->layout = 'default';
}
}
The best sollution I think is to configure the request handler in before filter after the mobile browser was detected in your app controller:
public function beforeRender() {
if($this->RequestHandler->isMobile()) {
$this->theme = 'Mobile';//set your theme
$this->RequestHandler->ajaxLayout = 'public';//this does the trick, set your mobile layout, $this->layout is simply ignored or overwritten by the component
}
}
Related
I came across a situation where I don't need to show the header (it has the navigator bar and logo)andfooter` for a particular page in yii. There are a number of tweaks to do this. For example, having a check for a particular action where the layout will not load header and footer..
Does yii provide any thing solid for this issue?
Do we have anything like $this->layout->unsetHeader();? or $this->layout->unsetFooter();?
I don't want to have a check in the layout file to sort this out.
Help would be appreciated.
You can set $this->layout to false;
$this->layout = false
$this->render('view', $data);
This can also be achieved using renderpartial
$this->renderPartial('view', $data);
The approach above will display a page segment and not other items of the page layout (for example inclusion of javascript and css, and HTML headers).
If you want your layout files to have logic in it, you can pass variables from the controller.
$this->layout = 'mytheme';
$this->show_css = true;
$this->render('view', $data);
and in your layout
<html>
<body>
<?php if ($this->show_css) { ?>
<div id="menu">
<ul><li>Menu Option 1</li><li>Menu Option 2</li></ul>
</div>
<?php } <?
<div id="body">
<?php echo $this->content; ?>
</div>
<div id="footer">
</div>
</body>
</html>
If you don't want to use a variable in the controller. use a global variable instead.
Yii::app()->params['show_menu'] = true;
I haven't find function like you looking for.
I think the best and siplest way is however use a proper layout, and call it in controller in this way
public function actionYourView()
{
$this->layout='yourLayout';
$this->render('yourView');
}
In this way you don't need check inside the layout for header and footer the logic is all in the controller. And assign the proper layout is easy.
Full disclosure, I haven't worked with Ajax before. I am starting to read up on guides but time constraints have me panicking and looking here for help.
Working with Kohana and am trying to figure out how to implement an infinite scroll. The application has existing pagination set up.
I've found that by doing this in my script:
$.post('mycontroller/infinite', {page:page}, function(data) {
$('.mycontainer').append(data);
});
and setting up the action in my controller:
<?php
public function action_infinite(){
?><p>HELLO WORLD</p><?php
}
?>
The entire page is being appended to my div after the Hello World text. I set up an alert to see what was in data and it was literally the entire page of HTML starting with the p tag Hello World.
How do I go about returning a partial from my controller and not appending the entire page?
There are two ways to do infinite scrolling:
Return HTML that you can paste directly into the page
Return JSON data that you then use to generate and append HTML with Javascript
The first approach has the advantage that you don't need to rewrite your views twice. Assuming you're using plain old PHP templates, your code would go something like this:
Product page view:
<html>
<!-- blah blah blah -->
<div id="products">
<?php echo View::factory('products/page')->bind('page_num', $page)->bind('products', $products) ?>
</div>
<!-- blah blah -->
Page view
<?php foreach($products as $product): ?>
<div class="product"><!-- blah blah --></div>
<?php endforeach ?>
Page fetch controller
public function action_page()
{
$this->template->content = View::factory('products/page')->bind(...);
}
The main point is to separate the product page code from the actual code that renders the individual products. That way you can easily invoke only the product render code for things like infinite scrolling.
Note: I haven't used Kohana in years so could have made some minor mistakes.
OK so my main problem was that the entire page was in the response. I found out this was a Kohana thing. By placing this in my controller method:
$this->auto_render=false;
The response ceased to be bloated with HTML I didn't want.
Then I simply had to set my View::factory and echo it.
public function action_getjson()
{
$this->response->headers('Content-Type', 'application/json; charset=utf-8');
$this->auto_render = false;
$this->response->body(json_encode(['var' => 'blabla'));
}
I'm new to Symfony2 and I've been thinking of the best way to generate navigation bar HTML that is used on every page request - especially with regards to caching.
So imagine if every page request shows the logged in user and a number indicating how many messages are unread (in fact like stackoverflow for that). I'm guessing that could be generated in every controller to ensure the info is up-to-date (using a function or something of course) - but I'm also looking at caching the whole controller output, and think it might be good to keep this dynamic part separate.
Would creating a controller extension for all this kind of stuff be a good way to go? So this way the controller only deals with that specific function (e.g. getting blog posts from a DB etc.) and the controller extension adds all the dynamic content. That way I can cache the controller result and speed up pages without caching the full page (which can't really be done due to lots of dynamic HTML content).
Something like this maybe:
class ControllerExtension extends Controller
{
public function render($view, array $parameters = array(), Response $response = null)
{
//get number of messages for this user
$parameters['messages'] =
//are they logged in
$parameters['logged_in'] =
// render as normal
return parent::render($view, $parameters, $response);
}
}
For this I want to ignore use of JS. I know some of these things could be populated with JS, but I would prefer not for this.
You can solve this by caching the navbar fragment separably from the page html with ESI or Hinclude and can be simply and elegantly solved with Symfony2.
Embed a controller inside a template
You can render a controller inside a template:
<div id="sidebar">
{% render url('latest_articles', { 'max': 3 }) %}
</div>
This will render the controller with the route "latest_articles", inside your html.
This can be done in you controller template, or in the global layout template (where you define the header, footer, js, css ecc of all your pages, see Template Inheritance)
Cache the embedded fragment separately from the page html:
You can use a reverse proxy (like Varnish, or the AppCache), to cache the two part of the html separately:
<div id="sidebar">
{% render url('latest_articles', { 'max': 3 }, {'standalone': true}) %}
</div>
That's it, just add {'standalone': true}
You'll need an external program on front of your web server (like Varnish, or Nginx with a mod), but this is the fastest way.
Load the fragment with javascript:
You can also tell symfony to asynchronously load the fragment in javascript:
<div id="sidebar">
{% render url('latest_articles', { 'max': 3 }, {'standalone': 'js'}) %}
</div>
This is a nice approach, since you can cache the entire html in a CDN (for example with Amazon CDN CloudFront), and still show user specific content.
For info see: http://symfony.com/doc/2.1/book/templating.html#asynchronous-content-with-hinclude-js
Have recently started to re-develop an application with CodeIgniter and I am trying to implement my template into the system.
I am facing an issue that I can't yet see a way around
Basically, at the minute within the controller an example of what I am doing is:
/*
* Load view for header
*/
$this->load->view('header_view');
/*
* Load view for navigation
*/
$this->load->view('navigation_view');
/*
* Load view for content
*/
$this->load->view('content_view');
/*
* Load view for footer
*/
$this->load->view('footer_view');
However the problem I am facing is that the content area has pages dynamically loaded in to it.
So the navigation area links don't open up the HREF URL but they load that page data in to the content div via ajax.
I need to be able to go to my controllers directly via the URL such as 'http://www.website.co.uk/controller/method_name/parameters' which at the minute is fine.
The navigation however will load that link in to the content area which also includes the header/navigation/footer so I end up with nested layouts in the content area...
The simple way around it is 'well don't include the header/navigation/footer views in every page' however then you can't directly go to the URL such as above, it would only work when loaded in to the content area as it would need to have the header, navigation and footer.
The solution that I ideally need is that the header/navigation/footer are ALWAYS loaded around any controller so that if I go to a controller/method via the URL I don't have to load the header/navigation/footer in the controller but it is automatically loaded around it.
Any ideas appreciated, thanks
Why not extend the CI controller with a MY_Controller, then all your controllers will extend MY_Controller. In my_Controller have a function like:
public function loadView($file, $data=array()){
$this->load->view('header', $data);
$this->load->view($file, $data);
$this->load->view('footer', $data);
}
Then, from your controllers actions, just call it :
public function index(){
// code code code
$this->loadView('welcome', array('message'=>'Hello!'));
}
I think you get the point.
in ajax you can use views like this:
<div id="header"></div>
<div> //here all your stuffs</div>
</div id="footer"></div>
then just :
<script>
$(function(){
$('#footer').load('my_footer_view_url');
$('#header').load('my_header_view_url');
});
</script>
this is a poor example, you can define both a php method which serves the views and a js method which loads them into divs, so each view then must have only a <div> where to load partials
Important
if you can use Ajax, this solution is great, cause once you move the #footer div somewhere else in your views you moves an enteire footer view for example, php will be more static anyway, but it depends, i sad, if you can or not use ajax ;)
I feel my problem is relatively simple. I'm new to the Zend framework and I'd like to be able to call a controller to do some work for a header or a footer. I've already created a HeaderController and a applications/views/scripts/headers/index.phtml - all I'm trying to do is get that data, and put it in my layout by default.
Everything works if I navigate to /header, by the by.
Edit:
Made some progress - if I add:
$this->render("header/index.phtml");
it renders all the static data, but doesn't seem to be running the HeaderController.
Try this bit of code out, be sure to disable the layout in your header controller, as the purpose is only to render a limited amount of content.
<?= $this->action('index', 'header', null, array('possible_args'=>'here')); ?>
The documentation can be seen here.
http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.action