Ember.js recursive controllers and views - model-view-controller

Say I have a list of Action objects, which corresponds to a Ember model. Each has a few properties (timestamps) and a detail attribute, which can can recursively contain more details (arbitrarily deep nesting). You can think of the details as nested lists.
I want to write a UI that allows easy editing (auto completion of values, easy copy and paste, reorder elements, etc) of the detail for any Action object.
Right now, my DetailView template will recursively render additional DetailViews:
{{#if view.content.hasChildren}}
{{#each child in view.content.children}}
{{#DetailView contentBinding=child}}
{{/each}}
{{#else}}
{{#EditDetailView contentBinding=view.content.value}}
{{/if}}
So each DetailsView corresponds to a node in the Details object tree.
But I am unclear how to add controllers to the mix -- there is additional state I need to store / functionality to implement (e.g., transforming values from the Detail object for display in the DetailsView; handling events for inserting/deleting/reordering elements; changing the structure of the Details tree) that belongs neither in the model nor the view.
Ideally I would have a DetailsController serving as a proxy a Details per DetailsView. Can I dynamically instantiate controllers and set up their contents within a view template? My understanding of the new Ember Router is to setup controllers and outlets in in a given route; however, that doesn't seem to apply here because no routing is being done at all. All suggestions / insight about how to handle recursive controllers / views / routes welcome.
I've taken a look at EmberJS Nested Views and Controllers, but that proposes I have a single ArrayController for all Details, even across Actions ... this would not preserve the tree structure of the nested details either.
I've also looked at Recursive view in handlebars template not working after upgrading to Ember 0.9.6 but the solution doesn't say anything about controllers.

** UPDATE Feb 20, 2013 **
API documentation for the {{control}} helper is now available here. It warns that "The control helper is currently under development and is considered experimental."
To enable it, set ENV.EXPERIMENTAL_CONTROL_HELPER = true before requiring Ember.
** UPDATE Feb 3, 2013 **
A new helper {{control}} has been added to ember, implementing the Reusable Views proposal. So to have a DetailsController proxy a Details per DetailsView you can just:
{{control 'detail' child}}
See the {{control}} tests for example
Ideally I would have a DetailsController serving as a proxy a Details per DetailsView. Can I dynamically instantiate controllers and set up their contents within a view template?
Typically the way to do this would be via the handlebars {{render}} helper, which renders a template with an appropriate view and controller. Unfortunately you cannot use {{render}} to insert the same template more than once, so it cannot be used within an {{each}} block.
There was a lengthy discussion on the topic recently. See: Non-Singleton Controller Discussion!
Two solutions were proposed. The first involves adding an itemControllerClass property to ArrayController. If this property was set, the ArrayController would automatically wrap new contents in the specified class. This was added to ember a few weeks ago and takes care of most use cases, where you have a flat-list of items and want each to be wrapped in a proxy.
The second proposal, Reusable Views, allows you to provide a controller class to a view.
{{view UI.Calendar dateBinding="post.startDate" controllerClass="App.CalendarController"}}
This would create an instance of App.CalendarController for each UI.Calendar widget, which would be tied to the lifecycle of the widget. As of today this has not been implemented. See {{view}} should have an option to create a controller! for the latest status.
So AFAIK there is not a good way to accomplish this for the use case you outlined. Meantime, binding data to the view:
{{view App.DetailView contentBinding="child"}}
and then having some logic in the view itself seems reasonable. If/when Reusable View support is added to master you can pull that logic up into the controller.
See: https://github.com/emberjs/ember.js/issues/1766

Related

Show specific presenter instance to flex panel gwt mvp

I'm still learning GWT, yet already have to face some kind of challenge for a work I have to do. Can't show any specific code so I'll try to explain it well.
Here's the situation: A certain class "Navigator" creates and save the Presenter instances of my architecture to allow reusing them. There is a method show() inside that same class that actually displays the view related but that system only works full screen by calling RootPanel.get().
What i'd like to do is showing that presenter instance's view inside of a flex panel element declared in a class myView (related to a class myPresenter) that basically uses Flex Panel to structure it's content.
To make it maybe more clear:
class myView{
...
flexPanel.setWidget(firstWIdget)
flexPanel.setWidget(secondWidget) //secondWidget to be replaced by a "thirdWidget"
...
}
I'd like the secondWidget to be replaced by another one, let's call it thirdWidget, that consists of a specific presenter instance's view.
To resume, I'd like my presenter instance's view to not go full screen but only occupy a certain area of the screen.
The displaying is managed almost entirely programmatically, means very limited use of css files and no use at all of xml ui files.
How can I manage this ?
Thanks
Use a SimplePanel as a container for your views returned by your Navigation class instead of adding them directly to root panel, and use that instance of SimplePanel where ever you want.

Joomla Terminology: view, layout, task and component development

I'm a developer and I am very confident with MVC pattern and have already developed a lot of webapp from scratch using php framework like symfony or yii.
I'm a little bit confused about joomla mvc and terminology and after googling a lot, read joomla book extensions guide, read on joomla website my doubt are still there.
What is confusing for me is the component mvc structure and how I have to set up "my way of think" about joomla mvc, for doing the things in the joomla way.
In particular I am used to reasoning in terms of controller/action (like in symfony and yii framework)
So the final list of all my webapp url will be
controller1/action1
controller1/action2
controller1/action3
controller2/action1
controller2/action2
Each controller's action will decide what view to render and what layout to use for showing the view.
In particular in these frameworks, the definition of a layout is exactly the mean of a layout. And the view is the "core part" of the page.
So I can have a view with a list of users and I can put this view inside a mobile layout or a desktop layout, or to build a view for mobile and put it only in the mobile layout and so on.
The final result about directory structure in my webapp is something similar to the following:
controllers/
controller1
controller2
controller3
models/
modelForTableA
modelForTableB
views/
controller1/
viewForAction1
viewForAction2
layouts/
mobileLayout.php
desktopLayout.php
and for me is very clear to understand.
So finally my questions are:
how would be the directory structure in joomla?
what are in joomla the definition of view, layout and task?
I need to clarify that I do not need an explaination about MVC works in general, but if I would achieve the same result as before, how I have to organize my code and my work?
Suppose that I want to build a component with the following "url"
userController/addUser
userController/editUser
userController/listUsers
userController/viewUserDetail
anotherController/addOperation
anotherController/editOperation
anotherController/myNonCrudOperation
Thank you very much
Routing in Joomla is slightly different. The SEF URLs are built from menu items, which in turn point to a View/Layout combination.
This turns things around: a controller is not bound to a specific View/Layout.
Let's make an example of the flow with the addUser functionality you mentioned as an example; I'll be referring to these files (but you'll have plenty more):
/controllers/user.php
/models/user.php
/views/useradd/view.html.php
/views/useradd/tmpl/default.php
/views/useradd/tmpl/default.xml
/controller.php
/router.php
As you can see the layouts are inside each view's tmpl folder.
router.php
Let's start from this last file: router.php defines our custom SEF rules so, after Joomla passes the call to our component (usually with the params
?option=com_componentname) we can takeover and interpret the URL as we wish. It is a bit hard to get started with but does provide the most flexibility and power. We don't really need to implement it at all for this simple example: so back to our registration now.
First step: show the "new user" form.
You would typically bind this to a menu item, pointing to the /views/useradd/tmpl/default.php; the /views/useradd/tmpl/default.xml contains the definition of the layout so it's available in the menu manager. Very often there is only one layout per view.
Control is passed to the view /views/useradd/view.html.php , and the view will then load an instance of its own model (automatically chosen based on the view name, you can load other models of course) to gather any initialization data.
The view then renders the layout, and presents it to the user.
The layout's responsibility includes generating a form with an appropriate action (endpoint) and security tokens if appropriate:
<form action="index.php?option=com_mycomponent">
<input type="hidden" task="user.save">
<?php echo JHtml::_('form.token');?>
as you see it doesn't really matter if you want to use <input or params on the url, and you can most often mix them.
Form interaction
For autocompletion the form may need to invoke some backend controller methods, i.e. the method emailAvailable() in the /controllers/user.php
It does not make sense to have such functionality indexed, so we'll invoke the method directly with a non-SEF url:
index.php?option=com_ourcomponent&task=user.emailAvailable
followed by any other parameter. This will work in both get and post.
The controller /controllers/user.php's emailAvailable() method will return a json structure and then invoke exit() as we don't want the CMS to kick in at all. An alternative solution is to add the param &format=json in the call.
{"email":"johndoe#example.com", "available":true}
Saving the data
When the user submits the form, processing is first handled by the controller since a task is specified. (see above task=user.save). Joomla will invoke the method save() in the controller /controllers/user.php.
This time, however, our controller is responsible for returning information to the user. After processing the data, it may choose to re-render the registration form showing an error, or a thank you page. In either case the controller simply sets the redirect, letting Joomla handle the rendering when appropriate.
$this->setRedirect(JRoute::_('index.php?option=com_yourcomponent&view=useradd', false));
More control
Each time a controller task is not specified, the display() method of the main controller is invoked. You can add custom logic there.
Joomla fires several events during a view rendering; these can be intercepted by a system plugin or - if you add in the calls - other kinds of plugins as well. You may even create your own types of plugins. Do not try to instantiate a view manually from a controller, as this may inhibit plugin firing.
Small insight,
1) Directory Structure
controllers/
controller1
controller2
controller3
models/
modelForTableA
modelForTableB
views/
layout1
2) View and layout and task
check this answer
3) More routing techniques with SEF.
Hope it helps.
solved with this. I cannot delete this question because there already exists other answer.
Could any moderator close or delete this? Thank you
https://joomla.stackexchange.com/questions/18774/joomla-terminology-view-layout-task-and-component-development/18799#18799

dojox mvc at() target

I've created a sandbox with a demonstration of binding UI components to both data and state: http://dojo-sandbox.net/public/51073/1
It's my plan to generate code from a page definition creating a page-level widget which is templated. This widget will have its own scope, where the model and state will reside, which I am trying to simulate in the sandbox by way of the Page object.
The sandbox is working because the Page object is in the global state, which appears to be the default context for object resolution in mvc binding.
However the plan is to have a view widget supporting each page with both the Model and State contained within the widget's scope. The generated template for the view would be bound to both the Model and the State. I can establish the source via the 'target' property, but when the same UI component must be bound to two different models, one for value and one for state, the single source doesn't support this.
The Model data will come to me from the back-end, and the State data is derived via the State.Execute method once the Model data is present.
I've taken a look at the 'rel:' parameter of at(), but don't see how to leverage this syntax within a specific context, ie my view widget's scope. It seems to be working fine for the default global scope.
Is there a standard way to direct the data-dojo-props value binding at one source, and the data-mvc-bindings for attributes at another? Or, more precisely, what is the at('rel:') syntax which will support specifying the context of the relation, and not rely on the 'target' of the widget or containing widget?
If there is no way to specify the 'target' at this level, I will generate more logic in the Execute method to specifically set the html attribute on the component during state compilation.
data-mvc-bindings is for allowing non-widgets use dojox/mvc/at. If a widget is declared for an element data-dojo-props is the one for use instead.
If target is specified via data-dojo-props or data-mvc-bindings, it’ll be set eventually to the widget.target. ”rel:” syntax looks for a widget having .target up in DOM tree.
It means that one “group” cannot have more than one "relative binding target”, in case it’s one of your questions. You can have a “scope object” that contains pointers to more than one models and use it as a “relative binding target”, that may serve a similar purpose:
<div data-dojo-type="dijit/_WidgetBase"
data-dojo-props="target: {model0: model0, model1: model1}">
<input type="text"
data-dojo-type="dijit/form/TextBox"
data-dojo-props="value: at('rel:model0', 'value'),
disabled: at('rel:model1', 'disabled')" />
</div>
A working example can be found at http://jsfiddle.net/asudoh/M3bRC/. Hope these help.
Best, - Akira

Is there any reason to use target="view" or target="controller" in Ember actions?

I'm playing with actions in Ember and I see that some people use targets that point to their controllers or their views like such:
{{action saveNote target="view"}
However, I also see that Ember supports event bubbling much like the DOM, in that events will work their way up to the application controller and router.
Is there a reason for specifying either "view" or "controller"? If I understand it correctly, the view/controller that the template's action belongs to will be the first in line to receive the event, so why specify it?
There's really no reason to target the controller, since it's the default target. Events not handled by the controller will bubble up from the controller to the routes.
However, if you want the view to respond to an action, you'll need to target it explicitly.
target="controller' is not needed ( anymore? )
target="view" can have many uses which are perhaps local to a specific view instead of belonging into a controller. Like toggling the display of an item.
But target also has other use cases like if you want to target a controller you have declared in needs which is then accessible in controllers.<nameOfController>

Is Ext JS's MVC an anti-pattern?

I work in a team of 25 developers. We use ExtJS MVC pattern of Sencha. But we believe that their definition of MVC is misleading. Maybe we might call their MVC an anti-pattern too.
AMAIK, in MVC controller only knows the name or the path of the view, and has no knowledge on the view's internal structure. For example, it's not the responsibility of the controller, whether view renders the list of customers a simple drop down, or an auto-complete.
However, in Ext JS's MVC, controller should know the rendering of view's elements, because controller hooks into those elements, and listens to their events. This means that if an element of the view change (for example a button become a link), then the relevant selector in the controller should change too. In other words, controller is tightly-coupled to the internal structure of the view.
Is this reason acceptable to denounce Ext JS's MVC as anti-pattern? Are we right that controllers are coupled to views?
UPDATE (March 2015): Ext 5.0 introduced ViewControllers that should address most of the concerns discussed in this thread. Advantages:
Better/enforced scope around component references inside the ViewController
Easier to encapsulate view-specific logic separately from application flow-control logic
ViewController lifecycle managed by the framework along with the view it's associated with
Ext 5 still offers the existing Ext.app.Controller class, to keep things backwards-compatible, and to give more flexibility for how to structure your application.
Original answer:
in Ext JS's MVC, controller should know the rendering of view's elements, because controller hooks into those elements, and listens to their events. This means that if an element of the view change (for example a button become a link), then the relevant selector in the controller should change too. In other words, controller is tightly-coupled to the internal structure of the view.
I actually agree that in most cases this is not the best choice for the exact reasons you cite, and it's unfortunate that most of the examples that ship with Ext and Touch demonstrate refs and control functions that are often defined using selectors that violate view encapsulation. However, this is not a requirement of MVC -- it's just how the examples have been implemented, and it's easy to avoid.
BTW, I think it definitely can make sense to differentiate controller styles between true application controllers (control app flow and shared business logic, should be totally uncoupled from views -- these are what you're referring to), and view controllers (control/event logic specific to a view, tightly-coupled by design). Example of the latter would be logic to coordinate between widgets within a view, totally internally to that view. This is a common use case, and coupling a view-controller to its view is not an issue -- it's simply a code management strategy to keep the view class as dumb as possible.
The problem is that in most documented examples, every controller simply references whatever it wants to, and that's not a great pattern. However, this is NOT a requirement of Ext's MVC implementation -- it is simply a (lazy?) convention used in their examples. It's quite simple (and I would argue advisable) to instead have your view classes define their own custom getters and events for anything that should be exposed to application controllers. The refs config is just a shorthand -- you can always call something like myView.getSomeReference() yourself, and allow the view to dictate what gets returned. Instead of this.control('some > view > widget') just define a custom event on the view and do this.control('myevent') when that widget does something the controller needs to know about. Easy as that.
The drawback is that this approach requires a little more code, and for simple cases (like examples) it can be overkill. But I agree that for real applications, or any shared development, it's a much better approach.
So yes, binding app-level controllers to internal view controls is, in itself, an anti-pattern. But Ext's MVC does not require it, and it's very simple to avoid doing it yourself.
I use ExtJS 4's MVC everyday. Rather than spaghetti code, I have an elegant MVC app that has tightly defined separation of concens and is ridiculously simple to maintain and extend. Maybe your implementation needs to be tweaked a bit to take full advantage of what the MVC approach offers.
Of course the controllers are bound to the views in some way. You need to target exactly which elements in your views you want to listen to.
eg: listen to that button clicks or to that form element change or to that custom component/event.
The goal of MVC is components decoupling and reusability and the Sencha MVC is awesome for that. As #bmoeskau says, you have to be careful in separation of the view controllers (builtin for the view/widgets itself) and the application controllers (top level views manipulations) to take full advantage of the MVC pattern. And this is something not obvious when your read http://docs.sencha.com/ext-js/4-1/#!/guide/application_architecture. Refactor your MVC approach, create different controllers, create custom component, and embrace the full ExtJS MVC architecture to take advantage of it.
There's still a slight problem in Sencha approach IMHO, the MVC refs system doesnt really work when you have multiple instances of the same views in an Application. eg: if you have a TabPanel with multiple instances of the same Component, the refs system is broken as it will always target the first element found in the DOM... There are workarounds and a project trying to fix that but i hope this will be adressed soon.
I'm currently undergoing the Fast Track to ExtJS 4 from Sencha Training. I have a strong background in ExtJS (since ExtJS 2.0) and was very curious to see how the MVC was implemented in ExtJS 4.
Now, previously, the way I would simulate kind of a Controller, would be to delegate that responsibility to the Main Container. Imagine the following example in ExtJS 3:
Ext.ns('Test');
Test.MainPanel = Ext.extend(Ext.Container, {
initComponent : function() {
this.panel1 = new Test.Panel1({
listeners: {
firstButtonPressed: function(){
this.panel2.addSomething();
},
scope: this
}
});
this.panel2 = new Test.Panel2();
this.items = [this.panel1,this.panel2];
Test.MainPanel.superclass.initComponent.call(this);
}
});
Test.Panel1 = Ext.extend(Ext.Panel, {
initComponent : function() {
this.addEvents('firstButtonPressed');
this.tbar = new Ext.Toolbar({
items: [{
text: 'First Button',
handler: function(){
this.fireEvent('firstButtonPressed');
}
}]
});
Text.Panel1.superclass.initComponent.call(this);
}
});
Test.Panel2 = Ext.extend(Ext.Panel, {
initComponent : function() {
this.items = [new Ext.form.Label('test Label')]
Test.Panel2.superclass.initComponent.call(this);
},
addSomething: function(){
alert('add something reached')
}
});
As you can see, my MainPanel is (besides the fact that is holding both panels) also delegating events and thus creating a communication between the two components, so simulating sort of Controller.
In ExtJS 4 there is MVC directly implemented in it. What really striked me was that the way the Controller actually fetches the components is through QuerySelector which in my opinion is very prone to error. Let's see:
Ext.define('MyApp.controller.Earmarks', {
extend:'Ext.app.Controller',
views:['earmark.Chart'],
init:function () {
this.control({
'earmarkchart > toolbar > button':{
click:this.onChartSelect
},
'earmarkchart tool[type=gear]':{
click:this.selectChart
}
});
}
});
So as we can see here, the way the Controller is aware of the earmarkchart button and tool is through selectors. Let's imagine now that I am changing the layout in my earmarkchart and I actually move the button outside of the toolbar. All of a sudden my application is broken, because I always need to be aware that changing the layout might have impact on the Controller associated with it.
One might say that I can then use itemId instead, but again I need to be aware if I delete a component I will need to scatter to find if there is any hidden reference in my Controllers for that itemId, and also the fact that I cannot have the same itemId per parent Component, so if I have an itemId called 'testId' in a Panel1 and the same in a Grid1 then I would still need to select if I want the itemId from Panel1 or from the Grid1.
I understand that the Query is very powerful because it gives you a lot of flexibility, but that flexibility comes at a very high price in my opinion, and if I have a team of 5 people developing User Interfaces and I need to explain this concepts I will put my hands on the fire that they will make tons of mistakes because of the points I referenced before.
What's your overall opinion on this? Would it be easier to just somehow communicate with events? Meaning if my Controller is actually aware of what views he's expecting events, then one could just fire an event dosomethingController and the associated Controller would get it, instead of all this Query problem.
I think if you use the Sencha Architect to produce the Views then Inherit from that View to create Your own View.
Now this View Can be responsible to hook up to any events and raise meaningful events.
This is just a thought...
//Designer Generated
Ext.define('MyApp.view.MainView', {
extend: 'Ext.grid.GridPanel',
alias: 'widget.mainview',
initComponent: function() {
}
});
//Your View Decorator
Ext.define('MyApp.view.MainView', {
extend: 'MyApp.view.MainViewEx',
alias: 'widget.mainviewex',
initComponent: function() {
this.mon(this, 'rowselect', function(){
this.fireEvent('userselected', arguments);
}, this);
}
});
I think there is a pretty bad problem here - its very difficult to shard isolated units within a page.
The approach I'm experimenting with (which makes it somewhat easier to write tests aswell) is to have a vanilla js context object for each page which contains the logic (and has the benefit of being very easy to break up and delegate to different objects). The controllers then basically call methods on the context objects when they receive events and have methods on them for retrieving bits of the view or making changes to the view.
I'm from a wpf background and like to think of the controllers as code-behind files. The dialog between presenter/context and view is a lot chattier than wpf (since you dont have binding + data templating) but its not too bad.
Theres also a further problem I haven't had to solve yet - the use of singletons for controllers causes problems for reuse of UI elements on the same page. That seems like a serious design flaw. The common solution I've seen is (yet again) to pile everything into one file and in this case to ditch the controller altogether. Clearly that's not a good approach as soon as things start to get complicated.
It seems like getting all the state out of the controller should help though and you'd then have a second level of context objects - the top level one would basically just assign a unique id to each view and have a map of context=>view and provide dispatch to the individual context methods - it'd basically be a facade. Then the state for each view would be dealt with in the objects dispatched to. A good example of why statics are evil!

Resources