cancel
Showing results for 
Search instead for 
Did you mean: 

how to parameterize initialization of controllers

Former Member
0 Kudos

Say we have a controller <i>A_ctrl</i> and a model <i>A_model</i>. When initializing <i>A_ctrl</i> we would like to create/register the model and initialize it, something like:

...
A_model ?= create_model( class_name = '/path/toclass' model_id = me->model_id ).
A_model->set_something( me->some_parameter ).
...

Now, as one can see the initialization is parameterized with <i>me->model_id</i> and <i>me->some_parameter</i> ; since <i>do_init()</i>'s signature is empty, instance variables of <i>A_ctrl</i> are used.

However, how do we get the initialization parameters into <i>A_ctrl</i> (in non-BSP ABAP-OO the normal constructor would do the job)? In the view via <bsp:call>, <bsp:parameter> it is to late, because initialization has already taken place. If we don't initialize the model and leave this job (i.e. calling the methods <i>set_something()</i> etc.) to the creator of <i>A_ctrl</i> (probabely the super controller) itself, we would actually hold the creator of an object responsible for its correct/complete initialization - a job that objects typically are supposed do themselves (in 'normal' OO this is the one right to exist for constructors (right?)).

How is this dilemma solved?

Regards,

Sebastian

Accepted Solutions (1)

Accepted Solutions (1)

maximilian_schaufler
Active Contributor
0 Kudos

Hi Sebastian,

I think I understand the "dilemma" you are talking about.

If you want to keep your model initialization the "proper OO way", then you would probably need to change the point of time whis init is called. If you need some parameters for that, then just initialize your model at that time.

Of course, that could move the model-init out of the controller-init - another not-so-proper-OO way ...

But if there are parameters needed for initialization of your model, then these parameters are very likely to be just read once somewhere, being valid for the whole session - right?

So either get this parameter into controller-init, or initialize your model as soon as these parameters are available.

Maybe this is what it comes down to:

What kind of parameters do you need for your special case, and how do you retrieve them?

Here is how I deal with a similar situation:

In DO_INIT of my main controller, I create the model.

Then I set some very basic parameters to this model (like RFC destination for my calls), and afterwards call a self-written init-method of my model (that does the actual 'attribute-initialization').

Regards,

Max

Former Member
0 Kudos

Now we're talking Hello Max, hello Rainer, let me check whether I got the last paragraph of Max's reply right. In (super-)controller A you create and initialize (sub-)controller B's model (using the model's constructor or dedicated init-methods) and only then you let B register its (now initialized) model:


A, do_init():
..
b  = create_controller( name = 'B.do' id = 'b' ).
bm = create object b_model
       exporting
         someInitParameter  = ..
         someOtherParameter = ..
         owner = me .
b->set_model( bm ).
..

Hmm.. works and looks better. One has to be careful though that the code of the constructor contains a line if_bsp_model~init( id, owner ) where owner would be controller A.

In the meantime I found a solution that extends this:

Let me generalize the situation, say we want to create a generic component (~ controllermodelview) called 'tree' - and of course we want this component to be save, i.e. - topic of this thread - controller/model initialize themselves in a proper (OO-)way.

Now every user (other controller) of this component has to implement an interface 'tree_user' which contains a set of setter-methods. These setter-methods each get a reference to the tree-controller (and function as call-backs on the actual setter-methods on the tree-controller). Example:


do_init() of tree-ctrl:
DATA:
  parent     TYPE REF TO /namespace/if_tree_user,
  tree_model TYPE REF TO /namespace/cl_tree_model.

  parent ?= me->m_parent.

  parent->set_tree_title( me ).
  parent->set_tree_id( me ).
  parent->set..

  CREATE OBJECT tree_model
    EXPORTING
      im_tree_id   = me->tree_id
      ..
  
  set_model( model_id = me->model_id model_instance = tree_model ).

The controller that uses the tree component and that implements the interface now implements the setter-methods like

im_tree_ctrl->set_tree_title( 'OrgStructure' ).
etc.

E voilà, the do_init() of this controller now only contains something like

...
create_controller( controller_name = 'tree_ctrl.do' controller_id = 'org_struct_ctrl' ).
..

the actual initialization of tree controller/model is where it belongs (in the do_init()/constructor of tree_ctrl or tree_model respectively, not outside) and it is a compile-time error if a user of the component does not implement the tree_user interface!

Of course the user controller still has to implement the setters in a sensible way (here call back the setters of tree_ctrl itself), but this much one can expect.

Whatya think, from an OO point of view I am very satisfied now , would it be worth it writing a weblog about this?

Regards,

Sebastian

maximilian_schaufler
Active Contributor
0 Kudos

Hi Sebastian,

yes, looks like you understand what I tried to explain:

in do_init of main_ctr:

*) create model

*) call model init method

*) create sub-controller

*) call set_model for sub-controller

As for your extension:

I sure would like to read more about this, to have a small code example implementation of interface/setter methods. Gonna have to re-read this later as well (busy on that data binding thread atm) to fully get the grip on your example.

Answers (3)

Answers (3)

rainer_liebisch
Contributor
0 Kudos

Hi Sebastian,

let me explain my last reply a bit.

> note that A_model is the model of A_ctrl, not A_ctrl's supercontroller as your example suggests

My example doesn't suggest that. Note that I use the method get_model, not get_controller. But you're right, the usage is nearly the same. Each controller has a controller class which inherits from CL_BSP_CONTROLLER2, while the model class inherits from CL_BSP_MODEL. Both are classes where you can override some methods for your needs (you just have to redefine them in your class).

If you program ABAP-OO the constructor also is only there if you define him. It's the same with do_init.

Hoping this helps a bit.

Regards,

Rainer

rainer_liebisch
Contributor
0 Kudos

Hi Sebastian,

why don't you put your A_model stuff directly in the method do_init of the subcontroller if you want to handle it there?

If you already have created the model in the main controller you can use the method get_model to access it again. This could look like:


* Main Controller

DO_INIT
DATA: my_model TYPE REF TO cl_mvc_model.

my_model ?= create_model(
                 class_name = 'cl_mvc_model'
                 model_id   = 'mod1' ).
-------------------------------------------------------
* Subcontroller
* Attribute: model TYPE REF TO cl_mvc_model

DO_INIT
DATA: parent TYPE REF TO cl_bsp_controller2.

parent ?= me->m_parent.
model ?= parent->get_model( 'mod1' ).

model-> . . .

Regards,

Rainer

Former Member
0 Kudos

Hi Rainer,

> why don't you put your A_model stuff directly in the method do_init of the subcontroller if you want to handle it there?

Well, that is the core of the problem. When initializing the controller <i>A_ctrl</i> I'd like to initialize its model as well (self-evident I guess). However initialization of the model <i>A_model</i> is parameterized, i.e. I'd need a parameter in <i>do_init()</i> of the controller <i>A_ctrl</i> (note that <i>A_model</i> is the model of <i>A_ctrl</i>, not <i>A_ctrl</i>'s supercontroller as your example suggests). However <i>do_init()</i> is not a 'real' constructor, the signature is empty, no parameters can be passed, hence my question.

As described in my original posting I don't like the consequence that parts of the initializing process of a controller <i>A</i> (in this case the initialization of the controller's model) are handled somewhere outside the controller <i>A</i> itself - in BSP this would probably be the supercontroller of <i>A</i> which would first register <i>A</i> and then have the responsibility to call <i>A</i>'s own initializing methods.

Regards,

Sebastian

daniel_humberg
Contributor
0 Kudos

I don't know if this is what you looking for, but it might help.

if you set parameters of a controller like this:


navigation->set_parameter( name = 'a' value = a ).
navigation->next_page('A_ctr').

parameter a will not be available in do_init(), but if you do it like this:


CONCATENATE 'a_ctr.do?'
            'a='
            a
        INTO lv_url.
navigation->goto_page( lv_url ).´

it will be!

Former Member
0 Kudos

Hi Daniel,

please excuse my late reply. As for your proposal it might work if you use navigation (haven't tried it yet), however what if you are just not in the situation where navigation comes into play. Say the controller controls a (sub-)component of a view. It is created/registered in the supercontroller and called via <bsp:call>; in this common scenario there is just no navigation/redirect involved.

Regards,

Sebastian