Code Monkey home page Code Monkey logo

Comments (17)

johnyanarella avatar johnyanarella commented on July 20, 2024

@davidtucker and @ryancampbell were leading this effort, but they are currently tied up with some very exciting (but also very time consuming) client work. Initially, we kicked around some intriguing ideas related to routing (looking at innovative solutions in use on other platforms, such as: https://github.com/jverkoey/sockit). We are discovering that it's particularly difficult to design a routing implementation that scales across both mobile and desktop routing requirements. That said, we haven't given up.

As things stand, routing won't be part of 1.0. I'd like to slate it for the following release. So, we're probably talking a few months from now.

I'd be very interested to hear your opinion of the routing implementations currently available in the Sencha world, i.e. Sencha Touch's routing and Ext.ux.Router. Are there aspects of these solutions that you like or dislike? Considering your real-world application requirements, do either conceptually match your needs or are they too limited?

from deftjs.

zam6ak avatar zam6ak commented on July 20, 2024

I have found out that MVC routing implementation in not an immediate priority for Ext Js even thought it exists in Touch.
With that being said, Ext.ux.Router was created by Sencha professional services team member and was recommended for use. I am currently evaluating it for my project and will report back my experience.

from deftjs.

zam6ak avatar zam6ak commented on July 20, 2024

After trying to make Ext.ux.Router meet my app's requirements, I have decided to remove it. I think the extension is nice, but does not meet some of the required use cases that more complex apps would need. Furthermore, it depends on Ext JS History support which is not utilizing HTML5 History/State APIs. It becomes almost impossible to implement "skipping" on tab panels the user closes, for example. Also, there is very little you can do for redirects unless you modify the code (e.g. trying to pass in model id or similar). I came to the point where I modified the plugin so much, that I realized that I was almost writing something new, instead of just wanting to use routing in my Ext JS MVC app.

from deftjs.

Timopheym avatar Timopheym commented on July 20, 2024

@zam6ak I'm trying to add Ext.ux.Routing... but have some troubles with it.
btw, i found it not so flexible like it could be... so i wanna ask, have you developed your own implementation? Is there other tips?

from deftjs.

zam6ak avatar zam6ak commented on July 20, 2024

@Timopheym No I have not...:(

from deftjs.

brian428 avatar brian428 commented on July 20, 2024

In a simple app, the idea of using routing to jump to a specific UI is fairly straightforward. But I'm not really understanding how this would work for a complex app:

Say I have tabs, one of which is for Users. I click on the User tab, pick a record in a grid and click a Show Detail button. This expands a side panel containing the user details. I click edit, and the panel switches to an edit form.

Now, how can someone use a route to jump directly to the user details or user edit form? There are so many prior steps that must be done first (picking the tab, loading the users, selecting one, opening the detail panel, and going into edit mode) that I don't really see how this could happen automatically. To me, it requires a good bit of custom code to perform all of these steps...

from deftjs.

neonstalwart avatar neonstalwart commented on July 20, 2024

hi,

i don't use DeftJS at all (or Ext or sencha) but i have an interest in IoC containers in javascript and so i watch this project.

http://sourceforge.net/adobe/cairngorm/wiki/HowToUseCairngormNavigation/ describes what i think is a good approach to navigation. i've never used caringorm (or even flex) but the principles outlined there are something i've used in applications and it at least gives one option for how to approach complicated navigation scenarios. maybe it could be useful for you to consider some of the principles used in cairngorm.

from deftjs.

brian428 avatar brian428 commented on July 20, 2024

I've used that Navigation library in Flex projects, and it's quite complicated. It looks like adding something like this to DeftJS would be as complex (if not more so) than the entire current functionality of the DeftJS library. So unless my estimation is just way off, we're talking about doubling the size and complexity of the whole library just to add this feature. I'm pretty skeptical on whether it's worth all that work to add this.

I'm wondering if something more basic would work. So if you really need routing, we could parse the URL into a standard structure and hand it to a class/method that the developer writes to handle it. It would be up to them to actually write whatever code is needed to update the UI or load data to actually get the user to the right place in the application.

The other option might be something involving ExtJS's built-in State features, but that relies on cookies and/or LocalStorage. It also looks like that is ExtJS only - looking at the API docs, Touch doesn't appear to have State support.

from deftjs.

zam6ak avatar zam6ak commented on July 20, 2024

Another solution to UI navigation is to use finate state machines (state chart).
Here is an example:
http://stativ.us/

However, the idea behind routing in single page apps is for user to be able to bookmark the url and get to a certain view without navigating.

from deftjs.

johnyanarella avatar johnyanarella commented on July 20, 2024

The team discussed this problem at length early on in Deft JS's development before abandoning that feature as part of the 1.0 roadmap.

Creating a generalized solution for hierarchical view navigation based on arbitrary routes is extremely difficult. Without enforcing strict rules or conventions on the structure of components that comprise those views and on the format of URLs, creating a generalized solution might well be impossible. Even if we settled on a rigid set of rules to enable this generalized route-aware navigation functionality, as @brian428 said: implementing such as solution would adversely affect Deft JS in terms of size, complexity and flexibility.

What we understand now is that the problem was we were trying to do too much. The key is to avoid conflating A) managing URL state with B) managing navigation state. We can implement a solution for A, but the nature of B will vary for every application and with every development team's unique conventions and preferences.

In a future release (after 1.0), Deft JS will be adding a Router implementation that will make it easy to subscribe to particular URL patterns. It will be focused on managing the browser URL (History API and pushState) and allowing developers to easily observe and react to a particular route being triggered. It will leave the details of updating view state in response to those URL changes to the developer. Simple apps might have a single Router that is instantiated inside their primary ViewController, with routes mapped to methods that know how to modify view state accordingly. More complex applications will likely have multiple common Routers that are injected into key ViewControllers.

Primary influences on the current proposed architecture are:

Our focus is getting 1.0 out the door, but Routing will be one of the first post 1.0 features we will be pursuing.

from deftjs.

brian428 avatar brian428 commented on July 20, 2024

For no real reason, I was pondering this tonight and thought I'd see what everyone else thought. My idea is to try and keep this simple on the Deft JS side, while still allowing a developer to supply whatever routing logic is needed for their particular app. I don't really see how all the work could magically be done by Deft itself, since the set of possible actions that are needed to route someone deep into an application are virtually infinite.

Basic Option

So consider a basic setup where a RouteMapper is declared as a dependency:

Deft.Infector.configure(
    routeMapper: "MyApp.routing.RouteMapper" #Extends Deft.mvc.RouteMapper
)

When initialized, this class would check the URL for some pattern (possibly customizable as a config option). If the pattern matches, it parses the URL to obtain a "controller name", "action", and any additional parameters. It then attempts to look these up in the route mappings, which might looks like:

routes:
    user:
        detail: @someHandler

The handler method could be in the RouteMapper, or call another injected object, or call a static method on some other class, or defined inline, etc. However a developer wants to deal with it. It could fire events, create views, call service methods, or whatever else is necessary.

Fairly simple, yet open-ended enough to give people room to do whatever they need to in order to get things set up.

Similar, but a bit more structure...

That said, I also envisioned an expansion on that idea, which is a bit more complex but adds a bit more structure to what happens.

Again, the injector config:

Deft.Infector.configure(
    routingEventBus: "Deft.event.RoutingEventBus"
    routeMapper: "MyApp.routing.RouteMapper" #Extends Deft.mvc.RouteMapper
)

So same story here: route mapper parses the URL and looks it up in the mapped routes. Say it's controller "user" and action "details". For a given app, this may require switching to a user list tab, populating the list, then selecting a user to open a panel showing the details for that user. So the route mapping could be:

routes:
    user:
        detail: ( controller, action, params ) ->
            flow = [ 
                { event: "user.list", command: new MyApp.commands.UserListCommand( params ) },
                { event: "user.detail", command: new MyApp.commands.UserDetailCommand( params ) }
            ]
            @buildRouteFlow( flow )

Use of Commands wouldn't be mandatory (the developer can wrap up each "step" however they want to). What's important is the buildRouteFlow method, supplied by the superclass Deft.mvc.RouteMapper:

buildRouteFlow: ( flow ) ->
    chain = []
    for thisStep in flow
        chain.push( ( -> @buildPromise( thisStep.event, thisStep.command ) ) )
    return Deft.Chain.sequence( chain )

buildPromise: ( event, command ) ->
    deferred = Ext.create( "Deft.promise.Deferred" )
    @routingEventBus.fireEvent( event, command, ( proceed=true ) => 
        if proceed then deferred.resolve() else deferred.reject()
    )
    return deferred.promise    

John can probably see where I'm going with this. Each step in the route flow is wrapped in Promise, and all the steps are fed into a Promise Chain. Each step fires an event, which existing controllers can listen for. The existing controller can make async service calls, create views, etc. Once it's finished with its piece of work, it invokes the passed callback, which resolves that Promise and starts the next one in the chain.

Wrap up

Anyway, that's my (possibly crazy) take on how this could work. The first ("basic") option provides a wide-open gap for people to implement any approach they want to. If a bit more structure is desired, the routing bus and Promise chain option can be leveraged. But even that option isn't particularly complicated. This is really a post-1.0 topic anyway, but I figured I'd post about it since it was fresh in my mind.

P.S. It could get even kookier, where a Pipeline is used instead of a Chain, and each step dynamically determines the next command and feeds it into the next step in the pipeline. But now I'm just talking crazy. ;-)

from deftjs.

brian428 avatar brian428 commented on July 20, 2024

Just to add, the creation of the route flow could even be simplified, and Deft could just take the result of the route mapping function and pass it into buildRouteFlow automatically. So at its most basic, something like:

routes:
    user:
        detail: ( controller, action, params ) ->
            return [ 
                { event: "user.list", command: params },
                { event: "user.detail", command: params }
            ]

from deftjs.

juank11memphis avatar juank11memphis commented on July 20, 2024

Hello, I am Juan from Joukou, I will be working on the DeftJS Router task

from deftjs.

brian428 avatar brian428 commented on July 20, 2024

Hi, Juan. If you're going to take a stab at this for a pull request, my only advice is to post here with your plan on how this will work and the syntax you propose so that we can discuss and vet it before you spend a lot of time on implementing it.

from deftjs.

juank11memphis avatar juank11memphis commented on July 20, 2024

Hello Brian,

Ok, I will be posting the plan between today and tomorrow.

from deftjs.

juank11memphis avatar juank11memphis commented on July 20, 2024

Hello,

The plan for the DeftJS Router is to keep things simple for the first version and then add more features if needed.

The idea will be to have something very similar to BackboneJS giving users the responsability to update the UI for each route.

To create a new route class users will need to extend from "Deft.mvc.RouteMapper", this class will handle the following:

  • Listen to history events
  • Url matching
  • Executing callback functions everytime a url match a configured route

User will decide if they have all their routes in a single RouteMapper class or distributed in multiple ones.

Finally a "Deft.mvc.Router" class will be created, this will be a singleton that exposes basic navigation functions such as:

  • goToUrl(url)
  • goBack()
  • goForward()

In order to use the Router class users will need to require it in the Application file.
In order to initialize every RouteMapper they will need to declare them as a dependency in the injector config.

RouteMapper code example

Ext.define('MyApp.router.MyRouteMapper',{

  extend: 'Deft.mvc.RouteMapper'

  routes: {
    "login": "onLogin"
    "user/:userId": "onUserDetail"
    "user/:userId/projects": "onUserProjects"
    default: "onHomePage"
  }

  onUserDetail: (userId) ->
    #do whatever is needed to render the user details page

.....

})

Please let me know your thoughts.

from deftjs.

brian428 avatar brian428 commented on July 20, 2024

Hmm, maybe we can get John to comment. I was leaning more towards the solution I outlined above. What you're showing will technically work, but my worry is that it leaves an awful lot up to the developer to actually implement the "do whatever is needed to render the user details page".

Personally, I'd like to help the developer out a bit more and provide a bit more structure around how the routing works, so it isn't quite so much of a free-for-all.

By defining a built-in routing event bus, we can clearly define the steps involved in each route here in the route configuration, and allow any interested controller to observe the routing bus and do whatever it needs to do. It may also just be me (since I thought it up), but I found the use of a Promise Chain to wrap all the steps a very elegant approach. This would make it very easy for the ViewController handling each step to control when that step is done and allow the next step to start. I think this is important, since the steps will often involve running their own asynchronous processes (service calls, etc.) before the next step can start.

I'll pester John over IM to see if he can comment. (He just LOVES IT when I pester him heh.)

from deftjs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.