tag:robotlegs.tenderapp.com,2009-10-18:/discussions/problems/408-mobile-viewnavigatorapplication-navigator-accessRobotlegs: Discussion 2012-01-05T09:05:06Ztag:robotlegs.tenderapp.com,2009-10-18:Comment/108398522011-10-26T17:04:45Z2011-10-26T17:04:45ZMobile ViewNavigatorApplication navigator access<div><p>Hi Derek,<br>
There is a similar question in this thread:<br>
<a href=
"http://knowledge.robotlegs.org/discussions/problems/405-robotlegs-and-flex-mobile-startup-problems">
http://knowledge.robotlegs.org/discussions/problems/405-robotlegs-a...</a>
with links to 3 examples.</p>
<p>Personally, I would use the root display object (Application or
ViewNavigatorApplication or TabbedViewNavigatorApplication ) as a
contextView for a mobile app.</p>
<p>I would do it like this:</p>
<p><s:ViewNavigatorApplication<br>
xmlns:context="yourPathToTheApplicationContext.*"><br>
<fx:Declarations><br>
<context:ApplicationContext contextView="{this}"/><br>
</fx:Declarations></p>
<p>or like this:<br>
<s:ViewNavigatorApplication<br>
preinitialize="application_preinitializeHandler(event)"></p>
<p>import yourPathToTheApplicationContext.ApplicationContext;</p>
<p>protected var context:ApplicationContext;</p>
<p>protected function
application_preinitializeHandler(event:FlexEvent):void<br>
{</p>
<p>context=new ApplicationContext(this);</p>
<p>}</p>
<p><strong>ApplicationContext</strong></p>
<pre>
<code>
public class ApplicationContext extends Context
{
public function ApplicationContext(contextView:DisplayObjectContainer=null, autoStartup:Boolean=true)
{
super(contextView, autoStartup);
}
override public function startup():void
{
super.startup();
}
...
}</code>
</pre>
<p>Does this answer your question?<br>
Ondina</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/108398522011-10-27T20:41:56Z2011-10-31T17:09:03ZMobile ViewNavigatorApplication navigator access<div><p>Hi Ondina,</p>
<p>Thank you for your response. It does not answer my question. The
question I have is of using the navigator from the top level
application(ViewNavigatorApplication). In my example I map the
following value:</p>
<p>(application context)
injector.mapValue(ViewNavigator,(contextView as
ViewNavigatorApplication).navigator);</p>
<p>This gives me a reference to the top level applications
navigator property so that I can change the view stack from a
Mediator or Command if I wanted to with the following
injection:</p>
<p>[Inject] public var navigator:ViewNavigator;</p>
<p>I got this idea from the following discussion:</p>
<p><a href=
"http://knowledge.robotlegs.org/discussions/problems/263-mobileapplication-navigator-error">
http://knowledge.robotlegs.org/discussions/problems/263-mobileappli...</a></p>
<p>In which Max mentions injecting the navigator by mapping the
value:</p>
<p>(application context) injector.mapValue(ViewNavigator,
FlexGlobals.topLevelApplication.navigator);</p>
<p>What I am wondering is if it is better to use
FlexGlobals.topLevelApplication to reference the navigator, or if
it would be better to cast the contextView property in the
application context as the ViewNavigatorApplication to get the
reference to the navigator. It may just be a matter of personal
preference, but I have not seen any examples of
ViewNavigatorApplication mobile applications using robotlegs.</p>
<p>Thanks you again for your response,</p>
<p>Derek</p></div>derekbrignertag:robotlegs.tenderapp.com,2009-10-18:Comment/108398522011-11-01T13:34:47Z2011-11-01T13:34:47ZMobile ViewNavigatorApplication navigator access<div><p>Hi Derek,</p>
<p>Sorry for the late response. Your response to my response to
your question was hidden until yesterday, due to some tender
issues.</p>
<p>I’ll take another look at your question, and I’ll
try to give you a more thorough answer or an example, later today
or tomorrow.</p>
<p>One thing I can say right now:<br>
Personally I wouldn’t make use of the
FlexGlobals.topLevelApplication.</p>
<p>I would map a view stack, <strong>of any kind</strong>, to a
Mediator. I would let the ViewStackView handle the navigation and
if switching between the views in the stack should trigger other
actions, I would dispatch an event from the view, and the
ViewStackMediator would redispatch it to whoever would want to
listen.</p>
<p>Or if I’d like to change the ViewStack’s index due
to something happening elsewhere in the application, say a Model or
Service, I’d let the ViewStackMediator listen for an event
dispatched by the Model/Service. I would then call a public
function on the ViewStackView , that would change the stack’s
index to the one received through the event’s payload.</p>
<p>Model: dispatch (new StackEvent(StackEvent.INDEX_CHANGED,
viewStackIndex));</p>
<p>Mediator: eventMap.mapListener(eventDispatcher,
StackEvent.INDEX_CHANGED, onIndexChanged);</p>
<p>protected function onIndexChanged(event: StackEvent):void<br>
{</p>
<p>view.changeStackIndex(event.payload);</p>
<p>}</p>
<p>View:<br>
public function changeStackIndex(viewStackIndex:int):void<br>
{</p>
<p>someViewStack.selectedIndex =viewStackIndex;</p>
<p>}</p>
<p>Now, that works for a common Flex ViewStack. I’ll have to
see if it works like this with a ViewNavigatorApplication/
TabbedViewNavigatorApplication and ViewNavigator and if it answers
your question:</p>
<p>“This gives me a reference to the top level applications
navigator property so that I can change the view stack from a
Mediator or Command if I wanted to with the following
injection:”</p>
<p>Till then,<br>
Ondina</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/108398522011-11-02T11:31:00Z2011-11-02T18:42:39ZMobile ViewNavigatorApplication navigator access<div><p>Hi Derek,</p>
<p>I’ll attach an example of a TabbedViewNavigatorApplication
and here is a link to the repository on github, and a fxp file:<br>
<a href=
"https://github.com/Ondina/robotlegs-incremental/tree/master/robotlegsincremental/robotlegs-mobile-tabbed">
https://github.com/Ondina/robotlegs-incremental/tree/master/robotle...</a><br>
<a href=
"https://github.com/Ondina/robotlegs-incremental/blob/master/robotlegs-incremental-fxps/robotlegs-mobile-tabbed.fxp">
https://github.com/Ondina/robotlegs-incremental/blob/master/robotle...</a></p>
<p>In here, I’ll paste just the code of interest for our
discussion.<br>
The ContextView is a TabbedViewNavigatorApplication container with
2 Views: SomeView and AnotherView. On creationComplete I add an
event listener for the tabbedNavigator’s IndexChangeEvent.
When the tabbedNavigator.selectedIndex changes, the view dispatches
the SomeViewStackEvent.STACK_INDEX_CHANGED, with the selectedIndex
as a payload<br>
ApplicationMediator, which is the Mediator for ContextView listens
for this event, and, if need be, it can re-dispatch it.<br>
1. That’s the way from <strong>ContextView ->
ApplicationMediator ->rest of the Application</strong><br>
2. The other way around is from <strong>somewhere in the
Application-> ApplicationMediator-> ContextView</strong>.<br>
In my example SomeView contains a list. If the user selects an
item, SomeView dispatches<br>
SomeViewStackEvent.STACK_INDEX_CHANGED, with the selectedIndex as a
payload,<br>
SomeMediator listens for that event and re-dispatches it.<br>
ApplicationMediator listens for the event dispatched by
SomeMediator and does this:<br>
view.changeStackIndex(event.viewStackIndex);<br>
In the changeStackIndex method of the ContextView:<br>
tabbedNavigator.selectedIndex= viewStackIndex;<br>
That’s all:)<br>
Now, since I’m a flex-mobile-applications newbie, I
can’t say how it works with other scenarios, where you want
to push/pop a View. I’d have to try it, but I’m pretty
sure that the logic of using the mediator of one of the
navigator-containers as a bridge between the application and the
view is applicable as well. I wouldn’t manipulate views in
commands (exception to the rule would be a popup).</p>
<p>If you have a simple example with your specific scenario, we
could take it from there.<br>
I haven’t had the time to take a proper look at Mike’s
example (see the other thread I linked to), so I can’t say if
it’s what you need, but at least it could inspire you</p>
<p>Here are the code snippets:<br>
<strong>ContextView.mxml</strong> is the root display object. It is
a TabbedViewNavigatorApplication:</p>
<pre>
<code>
TabbedViewNavigatorApplication
ViewNavigator id="someView"
label="SomeView"
firstView="com.robotlegs.demos.robotlegsincremental.views.components.SomeView"
ViewNavigator id="anotherView"
label="AnotherView"
firstView="com.robotlegs.demos.robotlegsincremental.views.components.AnotherView"
TabbedViewNavigatorApplication></code>
</pre>
<p>The script in ContextView:</p>
<pre>
<code>
import com.robotlegs.demos.robotlegsincremental.ApplicationContext;
import com.robotlegs.demos.robotlegsincremental.controllers.events.SomeViewStackEvent;
import mx.events.FlexEvent;
import spark.events.IndexChangeEvent;
protected var context:ApplicationContext;
protected function application_preinitializeHandler(event:FlexEvent):void
{
context=new ApplicationContext(this);
}
protected function application_creationCompleteHandler(event:FlexEvent):void
{
tabbedNavigator.addEventListener(IndexChangeEvent.CHANGE, onStackIndexChange);
}
public function changeStackIndex(viewStackIndex:int):void
{
if (viewStackIndex != -1 && viewStackIndex < tabbedNavigator.length)
tabbedNavigator.selectedIndex=viewStackIndex;
}
protected function onStackIndexChange(event:IndexChangeEvent):void
{
dispatchEvent(new SomeViewStackEvent(SomeViewStackEvent.STACK_INDEX_CHANGED, tabbedNavigator.selectedIndex));
}</code>
</pre>
<p><strong>SomeView.mxml</strong></p>
<pre>
View
List id="someViewList"
x="10"
y="18"
width="228"
labelField="somename"
change="someViewList_changeHandler(event)"
View
</pre>
<p>The code in SomeView:</p>
<pre>
<code>
import com.robotlegs.demos.robotlegsincremental.controllers.events.SomeViewStackEvent;
import mx.collections.ArrayCollection;
import spark.events.IndexChangeEvent;
public function setListDataProvider(dataProvider:ArrayCollection):void
{
someViewList.dataProvider=dataProvider;
}
protected function someViewList_changeHandler(event:IndexChangeEvent):void
{
dispatchEvent(new SomeViewStackEvent(SomeViewStackEvent.STACK_INDEX_CHANGED, event.currentTarget.selectedItem.someid));
}</code>
</pre>
<p><strong>ApplicationMediator.as</strong></p>
<pre>
<code>
[Inject]
public var view:ContextView;
override public function onRegister():void
{
eventMap.mapListener(eventDispatcher, SomeViewStackEvent.STACK_INDEX_CHANGED, onStackIndexChanged);
eventMap.mapListener(view, SomeViewStackEvent.STACK_INDEX_CHANGED, onStackIndexChangedFromStack);
}
protected function onStackIndexChanged(event:SomeViewStackEvent):void
{
view.changeStackIndex(event.viewStackIndex);
}
protected function onStackIndexChangedFromStack(event:SomeViewStackEvent):void
{
//can be redispatched to other actors
trace("ApplicationMediator.onIndexChangedFromView(event)" + event.viewStackIndex);
}</code>
</pre>
<p><strong>Somemediator.as</strong></p>
<pre>
<code>
[Inject]
public var view:SomeView;
override public function onRegister():void
{
eventMap.mapListener(view, SomeViewStackEvent.STACK_INDEX_CHANGED, dispatch);
}
protected function onDataUpdated(event:SomeModelEvent):void
{
view.setListDataProvider(event.someUpdatedData);
}</code>
</pre>
<p>Please, tell me what you think and why my approach
wouldn’t solve your problem.<br>
I’m willing to try your exact use case, if you let me know
about it:)<br>
Maybe other users will chime in as well.</p>
<p>Ondina</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/108398522011-11-02T11:32:58Z2011-11-02T18:55:51ZMobile ViewNavigatorApplication navigator access<div><p>the attachment:<br>
robotlegs-mobile-tabbed.zip</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/108398522011-11-03T09:26:16Z2011-11-03T09:26:16ZMobile ViewNavigatorApplication navigator access<div><p>Hi Derek,<br>
I’m looking now at Mike’s example, and I think it
answers your question.<br>
In his Context he does:<br>
injector.mapValue(ViewNavigator, (contextView as
ViewNavigatorApplication).navigator)<br>
and<br>
injector.mapSingleton(NavigatorManager);</p>
<p>Then he injects the ViewNavigator in the NavigatorManager<br>
[Inject] public var navigator:ViewNavigator;</p>
<p>public function gotoView(viewClass:Class, data:Object =
null):void<br>
{</p>
<pre>
<code> navigator.pushView(viewClass, data);</code>
</pre>
<p>}</p>
<p>public function goHome():void<br>
{</p>
<pre>
<code> navigator.popToFirstView();</code>
</pre>
<p>}</p>
<p>It’s a cool solution.<br>
My preference would be to let the View handle the navigation(push,
pop), though.<br>
I would use a command to dispatch an event to the mediator with the
viewClass as a payload. Not sure how right now, but I’m
curious how it works, so I will try it.</p>
<p>HTH</p>
<p>Ondina</p></div>Ondina D.F.tag:robotlegs.tenderapp.com,2009-10-18:Comment/108398522011-11-03T14:38:50Z2011-11-03T14:38:50ZMobile ViewNavigatorApplication navigator access<div><p>Hi Derek,</p>
<p>Here is what I did :</p>
<ol>
<li>SomeView (<a href=
"https://gist.github.com/1336453">https://gist.github.com/1336453</a>)
dispatches an event when the List’s index changes.</li>
<li>SomeMediator (<a href=
"https://gist.github.com/1336460">https://gist.github.com/1336460</a>)
re-dispatches it</li>
<li>SomeViewListEvent.LIST_INDEX_CHANGED triggers NavigationCommand
(<a href=
"https://gist.github.com/1336471">https://gist.github.com/1336471</a>)</li>
<li>NavigationCommand reads the payload, which is an id coming from
the SomeView’s List,</li>
<li>and the injected NavigationModel (<a href=
"https://gist.github.com/1336473">https://gist.github.com/1336473</a>)
provides it with the viewClass corresponding to this id stored in
stackViews:Array</li>
<li>The NavigationCommand(<a href=
"https://gist.github.com/1336471">https://gist.github.com/1336471</a>)
dispatches the</li>
<li>NavigationEvent.ACTIVE_VIEW_CHANGED (<a href=
"https://gist.github.com/1336468">https://gist.github.com/1336468</a>)
with the viewClass as a payload.</li>
<li>ApplicationMediator (<a href=
"https://gist.github.com/1336448">https://gist.github.com/1336448</a>)
listens for this event and in</li>
<li>the ContextView (<a href=
"https://gist.github.com/1336441">https://gist.github.com/1336441</a>)
the ViewNavigator goes to the specified view:
navigator.pushView(viewClass);</li>
</ol>
<p>The entire code is here:<br>
<a href=
"https://github.com/Ondina/robotlegs-incremental/tree/master/robotlegsincremental/robotlegs-mobile-navigator">
https://github.com/Ondina/robotlegs-incremental/tree/master/robotle...</a><br>
and the fxp here:<br>
<a href=
"https://github.com/Ondina/robotlegs-incremental/blob/master/robotlegs-incremental-fxps/robotlegs-mobile-navigator.fxp">
https://github.com/Ondina/robotlegs-incremental/blob/master/robotle...</a></p>
<p>If Mike would chime in too, we could discuss the alternative
solutions.<br>
Anyway, my point was, and still is, that you don’t need to
access the ViewNavigator in other parts of the application. Its
Mediator is the one who should communicate with the rest of the
app.</p>
<p>My question to you and Mike: are there use cases, where you
really need to have a reference to the ViewNavigator in a Model or
a Command? Maybe I don’t know enough about the intricacies of
the flex-mobile development yet, so I’d like to hear what you
think.</p>
<p>Thanks,<br>
Ondina</p></div>Ondina D.F.