element is rendered without layout - cakephp

I have books/index controller and view.
The view looks like this:
abcdef
123445
<?php echo $this->element('categorytree'); ?>
xyz
999
I have elements/categorytree element:
<?php
function my_function() { echo '123'; }
echo 'element is here!';
?>
And when I go to books/index in my browser, the element is rendered without layout so source output is:
abcdef
123445
element is here!
xyz
999
And when I remove function declaration in element the problem disappears - the whole layout is rendered - so the problem is when I declare any php function inside element, then if this element is "fetched" by any view only this element is rendered without a layout.
This problem appeared suddenly, I don;t know why...
Before I used functions declared in element and didnt have any problem...
------------------ solved
Wow this is strange - the problem was caused by the <!-- --> tags after the $this->element()...

Although you've found the solution to your problem, I'd just like to point out that defining functions in your view is a horrible practise. A better and cleaner way to do it is to create a custom helper, and simply use that.
A view is simply not the place to write functions or classes.

Related

How to modify $content_for_layout in CakePHP 1.3

I am using CakePHP 1.3. In app/views/layouts/default.ctp I am using this:
<?php echo $content_for_layout;?>
According to CakePHP Application Development, by Ahsanul Bari and Anupom Syam,
"This line is mainly responsible for placing controller-rendered view
contents inside the layout. We must include this to tell Cake where to
place the action-specific controller-rendered views."
I was trying to figure out how to modify the content of $content_for_layout. But I guess that is not the kind of variable that I am supposed to modify to modify the layout. What I am trying to accomplish is to either modify $content_for_layout or create a new layout to customize some elements for an A/B testing experiment. Could you help me to better understand how to manipulate $content_for_layout? Thank you.
UPDATE 1:
I am configuring an A/B testing experiment. I have this in app/views/layouts/default.ctp:
<body>
..........
<div id="split-test-homepage-content-original">
..........
<?php echo $content_for_layout;?>
..........
</div>
<div id="split-test-homepage-content-redesign">
..........
<?php echo $content_for_layout;?>
..........
</div/>
</body>
With CSS I am hiding/showing either split-test-homepage-content-original or split-test-homepage-content-redesign depending on the version that the split test will show. But I am having problems because $content_for_layout is being rendered twice. Even though visually people only see one version but behind the scenes the page has $content_for_layout loading twice on the same page. This is causing all kinds of problems to me such as duplicate forms, JavaScript elements not working correctly as a result of duplicate variables, etc. What I want to do is to modify what $content_for_layout does for <div id="split-test-homepage-content-redesign">. One option I am considering is to use JavaScript so that in the jQuery(document).ready(function($) { section I can do something in the experiment so that if a variable contains a specific boolean value, I show one version or the other. Something like this:
if(javascriptvariable==true){ then use the following HTML for the view:
<div id="split-test-homepage-content-original">
..........
<?php echo $content_for_layout;?>
..........
</div>
else, the Javascript will take care of not displaying the above, but this:
<div id="split-test-homepage-content-redesign">
..........
<?php echo $content_for_layout;?>
..........
</div/>
Does the JavaScript approach make sense to you or should I do something about creating new layouts or modifying what $content_for_layout does? Thank you.
Duplicating content was definitely asking for trouble. I used a much better approach to manipulate CSS classes and ids only without duplicating content.

Decompile angular elements

We have a angular grid written by some guys here at work, the entire company uses it.
A td-cell could look like this
<td typeahead-cell="location as location.Name for location in getApiLocations($viewValue, mapping)" ng-model="mapping.selectedLocation">
{{mapping.getLocationNames()}}
</td>
The typeahead-cell directive will execute some custom code on the td, what it does is hookup some code so that if you double click or write in the cell it will go from display only to (in this case) typeahead. It does this by taking the html in the td cell (The td cell is already compiled by angular), wrap it with some custom code that does above functioanlly and then call $compile on the entire thing. This works with expressions above like {{mapping.getLocationNames()}} because they do not change when compiling so it can be compiled any number of times.
The problem I face now is that I try to use a more complex expression with ng-repeat. Problem is the first compile (Done directly by angular-core) will change html from example
from
<span ng-repeat="location in mapping.locations">...</span>
to
<!-- ngRepeat: location in mapping.locations -->
Then when our custom grid code executs it will try to compile the code above which will result in an empty since it compiles against a html comment.
This is the code that breaks
$element.html($compile(displayElement.html($element.html()))($scope));
$element is the td-cell that contains my orignal code that, when doing $element.html() it will take compiled code and try to use that. Wont work. Displayelement is a wrapper that will show when we are in displaymode.
I either need to decompile $elementbefor edoing $element.html or somehow move the content of the $element (td cell) compiled and hooked up.
Any ideas?
edit: I have somewhat solved it, doing this
$element.children().appendTo(displayElement);
displayElement.appendTo($element);
This will take the children from the td-cell and add them to the displayElement without actually breaking the original $compile. jQuery.children cant move <!-- comment --> elements so if you have an expression with ng directives like my repater above you need to wrap it in a dummy element like
<span><span ng-repeat="location in mapping.locations">...</span></span>
Any workaround for this?
Instated of that line if you can check with this
//Store it first on a variable if blank
var html;
if(!html) html = displayElement.html($element.html());
$element.html($compile(html)($scope));
Hopefully it will work. May be you need to manage the scope of the variable.
Final solution is this
$element.contents().appendTo(displayElement);
displayElement.appendTo($element);
It's very important to use contents and not children because childrenwill ignore text nodes which will not include the comments generated by ng-repeat directive.

angular-foundation and angular-translate: apply translation into attribute back-text

I'm using angular-translation and angular-foundation modules with AngularJS and have defined Foundation top-bar like this:
<top-bar custom-back-text="true" back-text="My back text">
[...]
</top-bar>
I need to apply translate filter to My back text. Already tried these two solutions but with no success:
example 1 - CODE
<top-bar custom-back-text="true" back-text="'BACK.KEY' | translate">
example 1 - TEXT IN MENU
BACK.KEY
example 2 - CODE
<top-bar custom-back-text="true" back-text="{{ 'BACK.KEY' | translate }}">
example 2 - TEXT IN MENU
'BACK.KEY' | translate
Do I something wrong or is there no possibility to achieve this with these two modules?
Used versions
angular-translate: 2.4.2
angular-foundation: 0.5.1
If you check the js source code of foundation you will find this piece of code that handles back button
if (settings.custom_back_text == true) {
$('h5>a', $titleLi).html(settings.back_text);
} else {
$('h5>a', $titleLi).html('« ' + $link.html());
}
$dropdown.prepend($titleLi);
So it creates new element and adds to dropdown, result of which is that it copies the value you specified in the back_text. By that time "translate" is not resolved so it copies whatever you put there.
A quick hack to do to solve it you could listen for language change by doing
$rootScope.$on("$translateChangeSuccess", function...
As you can see in the piece of code from foundation.js it creates "a" element inside "h5", so you can do something like this
$rootScope.$on("$translateChangeSuccess", function(){
angular.element(".dropdown h5>a").html($filter('translate')('BACK'))
})
where "BACK" is the key used for translation.
But keep in mind that it's not a good practice to manipulate DOM inside controller, so you may create directive for that.
Though there may be better way to achieve it, this could be just quick hack to do the thing.

Why is the region in Drupal blank?

I my .info file I have this:
regions[footermenu] = Footer Menu
The region--footer.tp.php has this:
<?php
print render($page['footermenu']);
?>
I've placed a menu block in the "Footer Menu" (it shows up under structure->blocks). However, it's blank. If I place the block in region I know works the menu content is seen fine. Any idea why the region wouldn't see the block?
It may just be a typo in your question, but check that the template's file name ends with '.tpl.php'.
The code that triggers the rendering of your region, namely <?php print render ($page['footermenu']); ?>, goes in 'page.tpl.php', which in turn will render 'region.tpl.php' (or 'region--footermenu.tpl.php' in your specific case).
You will have to clear the theme's cache when you add a new template file. That can be done simply by visiting your theme's settings page.

CakePHP Elements - how to put javascript?

I've just started using cakephp elements and they're awesome (I used to use include).
I have an element gallery and an element called comments (for a certain page) and for them I have some javascript code attached to both of them. Do you have any suggestions on how I could include that javascript code in the element? If I simply add it like that it will load javascript before loading the html after the element and I don't think it's very wise.
You could put the Javascript code directly into the element file, or put the Javascript code in into your webroot folder, <cake directory>/app/webroot/js/ and include the file in your layout by using the HTML helper:
echo $html->script("myCode");
If you're worried about the Javascript code executing before the page has completely loaded, then use window.onload or $(document).ready() if you're using JQuery.
If I understand you correctly, you want to have JS specific to a page loading in the header when you call a certain element, but that the JS could be different for each element. You also want the JS to be referenced at the beginning of your HTML document.
This is actually quite easy to do. Just make sure that you have <?php echo $scripts_for_layout; ?> in you <head> tag in the layout you are using.
Then, within the element, just do:
<?php $this->Html->script("js_file", array("inline"=>false)); ?>
js_file is the name of your JavaScript file in app/webroot/js/. In this case, the file would be called js_file.js but you must leave off the .js when referencing it as above.
It doesn't matter where abouts in the element file you put this because the "inline"=>false part ensures it won't actually appear at that stage in the code. Instead, it will appear in the <head> wherever you put <?php echo $scripts_for_layout; ?> in your layout.
In cakephp 3 instead of array('inline' => false) you should use array('block' => true) if anyone is looking for that answer like I was.

Resources