Getting view to use correct region automatically - view

As mentioned in an earlier question of mine, I'm new to ATK4 and I'm currently learning, so there might come a few more question. Now to my issue.
I've created a region "Sidebar" in my template shared.html and adding the view to it like this:
class Frontend extends ApiFrontend {
function init(){
parent::init();
/*
Other stuff here
*/
$this->addLayout('Sidebar');
}
function layout_Sidebar() {
$this->add('View_Menu', null, 'Sidebar');
}
}
Then I'm creating the view like this:
class View_Menu extends AbstractView {
function init(){
parent::init();
$this->add('HtmlElement')
->setElement('a')
->setAttr('href', 'testurl')
->set('Link');
}
}
This gives me the following error:
Spot is not found in owner's template
Additional information:
spot: Content
Supplying the add function with $this->template->top_tag as third argument solves this problem:
$this->add('HtmlElement', null, $this->template->top_tag)
->setElement('a')
->setAttr('href', 'testurl')
->set('Link');
...but do I really have to add that to every add() call in the view? It doesn't seem right and I'm quite sure it's not!

When you are creating AbstractView, you need to specify a default template. By default your AbstractView will use the region of from your shared.html. In other words AbstractObject assumes the template of the region it replaces.
when you create defaultTemplate() or pass 4th argument to the add() you can specify a different file to be used for template of your sidebar menu.
In either way - the template should contain a where output of any sub-elements will be displayed.
You may inherit from "View" class which already relies on the custom template containing just a . Your idea of using HtmlElement is just like this, because HtmlElement extends View.

Related

Automatically call a function when inside a certain module/controller

Is it possible to call a function in a certain module every request?
Let say I have module name called 'configuration', on this module, I have a list of controllers and list of functions/methods. What I want is to automatically pass my "Menu" to the View without manually passing it on each methods and controllers.
This menu is only available when inside the 'configuration module.
// I have extended the base controller to create common functions
ConfigureController extends \BaseController
{
protected function processMenu() {
}
}
// One of my controller that needs to render processMenu()
SetupController extends ConfigureController
{
public index()
{
// I want to optimize this portion so that I do not have to call it evertime
$pass_to_view = $this->processMenu();
// I need to pass it again and again
return View::make('setup')->with('data', $pass_to_view );
}
}
PS. sample code only
Thank you in advance!
Use the BaseController constructor method __construct() and within the SetupController's constructor call parent::__construct();
This is where the view composers come handy.
Put your menu in a partial, include it in you layout, then register a view composer (doc here: http://laravel.com/docs/4.2/responses#view-composers).
You can put your register code anywhere, for instance you could create a file composers.php in app and include it in your app/start/global.php.

Add method to be available in all Views

I would like to have a method available to all Views in my app.
I would like to be able to make calls like this:
<span>${ getDynamicText() }</span>
The most obvious ways (to me) to implement this are:
Call the method in the controller and and pass it to the View.
Make the method static on some Util class and call it from the code ${ UtilClass.getDynamicText() }
Using meta programming to somehow make the method available to all Views.
The benefit of #3 is that the change would only have to be made in one place. #1 would have to be made in each controller action; and #2 would need an import on every View page which wants to use the method.
So is there a way to add a method to be available to all views in my app?
I have to admit I don't know in a lot of detail how .gsp files are processed behind-the-scenes so maybe they don't have a corresponding class and therefore can't be manipulated in this way. Links to good articles/docs will get extra good karma.
GSPs are compiled into classes that extend org.codehaus.groovy.grails.web.pages.GroovyPage, so you can add methods to that metaclass and they'll be available to all GSPs. The best place to do this is in BootStrap.groovy (or in a plugin's doWithDynamicMethods closure):
import org.codehaus.groovy.grails.web.pages.GroovyPage
class BootStrap {
def init = { servletContext ->
GroovyPage.metaClass.getDynamicText = { ... }
}
}
The recommended way to reuse functionality across GSPs is to define it as a tag, e.g.
class MyTagLib {
static namespace = 'my'
def dynamicText = {attrs ->
out << 'not very dynamic'
}
}
You can then call this tag in a GSP using:
<my:dynamicText/>
4th way: make a class/service that have method '.getDynamicText' and put it's intance into request at before filter ( request.setAttribute('x', myDynamicTextGeneratorObject) )
Now you can use x.dynamicText in any GSP
This is how I would do it:
Add a new class to your controllers folder containing your method
Do a grails install-templates
Navigate to the templates: \src\templatesscaffolding
Add the extends part to the controller template: class ${className}Controller extends NewController
re-generate your controllers
You can now use the method in every class and gsp.

Codeigniter models loaded in controller overwritten by models loaded in models

I'm having Codeigniter object scope confusion.
Say I load a model in a controller:
$this->load->model('A');
$this->A->loadUser(123); // loads user with ID 123
// output of $this->A now shows user 123
$this->load->model('B');
$this->B->examineUser ();
// output of $this->A now shows user 345
class B extends Model
{
public function examineUser ()
{
$this->load->model('A');
$this->A->loadUser(345); // loads user with ID 345
}
}
I would have thought that $this->A would be different from $this->B->A but they are not. What is the best solution to this issue? It appears the ->load->model('A') in the examineUser () method does nothing because it was loaded in the controller. Then the call to loadUser () inside that method overwrites the stored properties of $this->A. This seems like a bugfest waiting to happen. If I needed global models, I would have use static classes. What I wanted was something scoped pretty much locally to the model object I was in.
Is there a way I can accomplish this but not go way outside of CI's normal way of operating?
Followup/related:
Where do most people put there "->load->model" calls? All at the beginning of a controller action? I figured it would be easier -- though perhaps not excellent programming from a dependency injection perspective -- to load them in the model itself (construct or each method).
Whenever you use the Loader Class ($this->load->), it will load the object into the main CI object. The CI object is the one you keep referring to as $this->. What you've done is load model A twice into the CI object.
Essentially, all object loaded using the Loader class goes into a single global scope. If you need two of the same type, give them different names, as per $this->load->model('A','C'). I don't know of any way around it unless you revert to using bog-standard PHP.
In my team's code, we generally load the models in the controller's constructor, then load the data to send to the view in the function, often _remap().
This is not how the loader works sadly. CodeIgniter implements a singleton pattern, which will check to see if the class is included, instantiated and set to $this->A then will be ignored if loaded again. Even if you are inside a model, $this->A will be referenced to the super-instance via the __get() in class Model. Alis it, or just do:
class B extends Model
{
public function examineUser ()
{
$user = new A;
$user->loadUser(345); // loads user with ID 345
}
}
Here's what I've decided to do, please comment if you have advice:
I've extended the CI Loader class:
<?php
class SSR_Loader extends CI_Loader
{
function __construct()
{
parent::__construct ();
}
/**
* Model Retriever
*
* Written by handerson#executiveboard.com to create and return a model instead of putting it into global $this
*
* Based on original 2.0.2 CI_Loader::model ()
*
*/
function get_model($model)
{
if (empty ($model))
{
return;
}
$name = basename ($model);
if (!in_array($name, $this->_ci_models, TRUE))
{
$this->model ($model);
}
$name = ucfirst($name);
return new $name ();
}
}
Do any CI guru's see a problem with that before I invest time in changing my code a bit to accept the return obj, ala:
// in a controller:
public function test ($user_id=null)
{
$this->_logged_in_user = $this->load->get_model ('/db/users');
$this->_viewed_user = $this->load->get_model ('/db/users');
$this->_logged_in_user->load($this->session->userdata ('user.id'));
$this->_viewed_user->load($user_id);
}
I could also do private $_logged_in_user to make it available in the controller but positively force it to be limited to just the current controller and not spill anywhere else, or I could just do $_logged_in_user = $this->load->get_model ('/db/users'); and limit it to just the current method, which is probably what I'll do more often.
This seems like a pretty straightforward way to "fix" this issue (I say "fix" b/c it's not really a bug, just a way of doing things that I think is a bad idea). Anyone see any flaws?

namespacing with js prototype framework

When you create a class in the name space of example.
em.components.grid
em.components.grid.Popup = Class.create(
{
initialize: function(params){
...
},
show:function(){
// create or show
}
});
Does this mean in other classes I have access to the show method if I use the namespace path above.
// Another class in prototype
em.components.grid.Popup.show();
Or does your new class your trying to access show from have to be in the same namespace.
Is namespacing kind of like packages in other languages. So by giving a namespace you can keep all your classes related to for example grid in one name space and possible other classes unrelated to grid in another namespace.
Update
This raises 2 other questions, lets say i create my class like above with the same namespace. Then in another js document I instantiate the class
var popup = new em.components.grid.Popup()
Then popup would be a global variable not? which I don't want to have in my files if possible. Seen as I have went to all the trouble of giving it a unique name space. To then create an instance of the class on a global variable somewhere else in a js file.
So in the case of a popup is it best to have it global or would it be best to create it on a rollover event and remove it on a rollout event.
//pseudo code
$$('domelementClass').observe('mouseover', function(event) {
var popup= new em.components.grid.Popup(event.target);
})
the issue I see with above is I have no reference to remove it on the rollout.
$$('domelementClass').observe('mouseout', function(event) {
popup.remove();
})
Namespacing has the same purpose of packaging, avoiding collision. As your example above shows, in JavaScript, you namespace functions and variables by making them properties of an object.
Does this mean in other classes I have access to the show method if I
use the namespace path above.
// Another class in prototype em.components.grid.Popup.show();
In this case no because 'show()' is an instance method, it can only be called once you have a new Popup. You can use your namespaced Popup as an instance in another class or if you want to call show like a static method in Java then you would call Popup.prototype.show();
var Popup = Class.create({
initialize: function(params){
alert("I exist");
},
show:function(){
alert("show!");
}
});
// Popup.show(); // would error:
// Uncaught TypeError: Object function klass() {
// this.initialize.apply(this, arguments);
// } has no method 'show'
Popup.prototype.show();
foo = new Popup();
foo.show();
Some useful links:
http://michaux.ca/articles/javascript-namespacing
http://blog.anselmbradford.com/2009/04/09/object-oriented-javascript-tip-creating-static-methods-instance-methods/

joomla 1.5 multiple models, problem with default view

I'm developing a view that need to reuse a model, I'm following this documentation http://docs.joomla.org/Using_multiple_models_in_an_MVC_component. But that reference do the trick just (at least as far as I understand) when I use the parameter get task. if I use the view, joomla get me null data.
more clearly
controller.php - the task I named as the view I need
function viewdowhatIneed(){
$view = & $this->getView('viewdowhatIneed',html);
$view->setModel( $this->getModel( 'thenotdefaultmodelthatIneed' ), true );
$view->display();
}
model - thenotdefaultmodelthatIneed.php
class BLAModelthenotdefaultmodelthatIneed extends Jmodel{
function getReusableData0(){...}
function getReusableData1(){...}
}
view - view.html.php
class BLAViewviewdowhatIneed extends JView{
function display($tpl=null){
$dataneedit0 = $this->get('ReusableData0');
$dataneedit1 = $this->get('ReusableData1');
$this->assignRef('dataneedit0',$dataneedit0);
$this->assignRef('dataneedit1',$dataneedit1);
parent::display($tpl);
}
}
SO, what happen to me is:
example.com/index.php?option=com_BLA&view=viewdowhatIneed -> variables(datadataneedit0,dataneedit1) == NULL
example.com/index.php?option=com_BLA&task=viewdowhatIneed -> variables(datadataneedit0,dataneedit1) == Get me right data
then, my question is, is there a way to do the same thing, by using view parameter without task parameter (btw, I know this could be not a important problem, but I'm not an expert and on this reference http://docs.joomla.org/How_Joomla_pieces_work_together, it says:
The task part may or may not exist. Remember that if you omit it you are defaulting to task=display
so I really want to know that. In other words, can my view force to check the controller or vice versa.
Thanks in advance, excuse my english

Resources