Thank you for reporting this bug. We will make it our priority to review this report.
  1. #1
    Sencha User
    Join Date
    Oct 2011
    Location
    Germany
    Posts
    50
    Vote Rating
    10
    apsq will become famous soon enough

      1  

    Default Too many singletons

    Too many singletons


    Although ExtJS's controllers being singletons can be chalked up as a design flaw, Sencha Architect 2 takes the cake by treating not only the custom views as singletons, but also the stores.

    Ideally, SA2 should allow for custom components to be more than just pickled config objects with extra boilerplate (*any* support for external classes would be nice, FWIW).

    In any case, SA2 should not force the user to create a new exact duplicate of a store just to have more than one instance of it. Especially not if you consider that there is no way to define subclasses of your stores and you therefore have to copy the entire class definition (including any functions and properties).

    There are probably technical reasons why this is easier than Doing The Right Thing, but this is a major pain point for larger applications that need actual modularity and may want to have more than one copy of a thing on the screen at the same time (and don't want to fully de-normalize their entire database for every view).

  2. #2
    Sencha - Architect Dev Team Phil.Strong's Avatar
    Join Date
    Mar 2007
    Location
    Olney, MD
    Posts
    1,953
    Vote Rating
    65
    Phil.Strong is just really nice Phil.Strong is just really nice Phil.Strong is just really nice Phil.Strong is just really nice Phil.Strong is just really nice

      0  

    Default


    Know that what you call singletons are not in fact as you say. The fact that you include the views, stores, etc in your application and/or controller merely ensures they are loaded. That is optional. Only your initial view is instantiated at startup. Stores that are included in the application are a bit more rigid.

    You can use alias/xtypes to define and instantiate instances that override certain configs and add others.

    I feel like I'm explaining this poorly so give me a concrete example and I'll be happy to show you how it should be done.

    Best,
    Last edited by Phil.Strong; 18 Jul 2012 at 12:12 PM. Reason: grammar
    Phil Strong
    @philstrong
    #SenchaArchitect
    Sencha Architect Development Team

  3. #3
    Sencha User
    Join Date
    Oct 2011
    Location
    Germany
    Posts
    50
    Vote Rating
    10
    apsq will become famous soon enough

      2  

    Default


    Quote Originally Posted by Phil.Strong View Post
    Know that what you call singletons are not in fact as you say. The fact that you include the views, stores, etc in your application and/or controller merely ensures their loaded. That is optional.
    I'm not sure if I am parsing your answer correctly, but if you're saying that they're not strictly speaking singeltons, then, yes, I know that. There is nothing stopping me from creating more than one instance at a time.

    The controllers are intended as singletons, however. That much is obvious (you can have more than one of each, but as the refs are absolute, that will just result in multiple copies doing the same thing -- for view-specific controllers take a look at DeftJS) and that is a design decision in ExtJS, not Architect.

    This is irrelevant to the complaint about Architect however.

    In fact only your initial view is instantiated at startup. Stores that are included in the application are a bit rigid.

    You can use alias/xtypes to define and instantiate instances that override certain configs and add others.
    You're mixing two problems: views and stores.

    Views aren't singletons indeed. They are subclasses of the views provided by ExtJS. The problem with views is that they can only be direct subclasses of what ExtJS provides. There is no way to define a subclass of a subclass in Architect unless you save it to the toolbox. I'm not entirely sure about the limitations when going that route, but it's certainly not as straightforward as it should be.

    The bigger issue and the main point of this complaint is how stores work in Architect:

    I feel like I'm explaining this poorly so give me a concrete example and I'll be happy to show you how it should be done.
    Okay, let's get to the point then.

    Imagine you have a tabbed file manager app. It consists of a tab pane with a single tab showing the contents of the current folder. You can click on folders and open them in a new tab, showing the contents of that folder. You can switch between the tabs to go back and forth between the opened folders.

    In Sencha Architect you would create a tab pane for the app itself and a view for the folder, possibly with a title set to the name of the selected folder, and some kind of container (say, a grid) to show the contents. You would also define a controller and a store.

    The controller's state is global rather than view-specific, so you'd either need to use DeftJS for a view-controller or track the active tab or somehow try to keep the controller stateless (which can be difficult in large-scale applications).

    The store should be view-specific as the view directly references it to show the contents of the current folder. The records contained in the different stores belong to the same superset of records conceptually (i.e. they are all files and folders on the same filesystem and could be moved from one folder to the other), but each store instance only represents a snapshot of a subset of them: only the files and folders contained in this specific folder, possibly even using a pager if the list is very long.

    This is where the real problem lies: when defining the store, Architect forces you to supply a storeId. StoreIds are instance-specific, not class-specific, so the only reason you might want to put them on the store is if you only want a single instance of it. In any other case, you will either have to override the storeId on the instance (making the definition on the class redundant) or run into issues with having more than one store with the same id.

    Also, when trying to add the store to the view, Architect provides you with the option of adding a store from a dropdown. This will not, however, result in the view getting a fresh instance of the chosen store, but just use the selected store's storeId.

    This mess is partially ExtJS's fault. With its MVC implementation it now has a split personality of a) having views use stores directly to populate themselves independently of any application-level controllers and b) having controllers use stores to manipulate their content to control the views.

    With ViewControllers (in DeftJS) this is remedied a bit by making it a good practice to access the store on the view directly (rather than referencing the store), but you still have to jump through hoops to make views reference store classes (and instantiate them on demand) rather than storeIds.

    This probably boils down to a bad design decision in ExtJS (letting multiple views reference the same store instance is a good idea, but somewhere down the line someone didn't understand the difference between instances and classes). However Architect perpetuates this nonsense by encouraging its users to create multiple class definitions (be they identical copies or subclasses -- the latter of which I don't think SA2 supports beyond the dodgy "add to toolbox") just so they can use more than one instance (via storeId) of the same store.

    All of this is relatively trivial to circumvent when dealing with a predetermined number of instances, but in an example like the one I gave you (which is not entirely removed from our real-world scenario) there could be a theoretically infinite number of instances of one and the same store, all of which need to have different storeIds if they are to be referenced from the view indirectly.

    Our current workaround is to define an additional property (`x-store`) that references the store class rather than the storeId, and to override Ext.define and Ext.applyIf so the configuration object is modified with `store` directly referencing a new, auto-created instance of the store `x-store` references (with a new, unique ID and everything) before the view is instantiated (as some views will throw if the store does not exist -- at least in SA2, see my other report). This makes the `store` property ExtJS/SA provides redundant except to prevent SA2 from crashing.

    Bottom line: ExtJS storeId references are broken. Either fix them in ExtJS or make SA2 do something more intelligent than embracing singletons for everything.

    PS: Also please sort out the usability of this forum. The big reply button is so prominent I keep on accidentally clicking it when I'm done writing an inline reply or edit. The auto-save prevents worse things from happening, but this is startling to say the least.

    EDIT: Maybe ExtJS should allow referencing the store class in addition to the storeId (a bit like how the refs work) and add an "auto-create" flag to the configuration. Then SA2 wouldn't have to bend over backwards to do something non-stupid.

  4. #4
    Sencha User
    Join Date
    Oct 2011
    Location
    Germany
    Posts
    50
    Vote Rating
    10
    apsq will become famous soon enough

      1  

    Default


    Ah, indeed. After setting the storeId to something else I now see that the `store` property on the view actually does keep in sync with the class name rather than the storeId.

    Architect still forces me to define a default storeId on the store, however. And storeIds still default to the store's class name; to quote slemmon from the docs comment on Ext.grid.Panel cfg store:

    A store defined in an MVC application and instantiated via an associated controller will have a storeId using the class name of the defined store if a storeId is not set explicitly in the definition.
    As far as I can tell, all Architect is doing is A: making sure stores use the class name as storeId by default and B: letting me pick a class name when trying to reference a store. As soon as the storeId and class name differ, it's entirely my job to make sure the store reference is resolved to something meaningful because otherwise ExtJS (via StoreManager.lookup) will just treat it as an unknown storeId.

    Excuse me, but this isn't a solution, it's a hack. Your answer seems to be to write controllers to take care of every instantiation that uses a fresh store, which is impossible for views that aren't promoted to classes (because the relevant configuration is buried inside initComponent in an applyIf call).

    The only way to avoid duplicating code (be it store definitions or controller methods) seems to be to override Ext.define and Ext.applyIf as I have mentioned. Allowing the user to enter arbitrary text for the `store` property is not the same as supporting dynamically instantiated stores.

    PS: Please use a spell checker or proof-read your posts better. As a non-native speaker I find it extremely hard to follow what you're trying to say.

  5. #5
    Sencha - Architect Dev Team Phil.Strong's Avatar
    Join Date
    Mar 2007
    Location
    Olney, MD
    Posts
    1,953
    Vote Rating
    65
    Phil.Strong is just really nice Phil.Strong is just really nice Phil.Strong is just really nice Phil.Strong is just really nice Phil.Strong is just really nice

      0  

    Default


    We agree that the framework does not provide an elegant solution for multiple views using the same store. Likewise, for multiple views using slightly different stores (filters, sorts, storeIds).

    To date, Architect has done nothing to improve this and for that I'm sorry.

    Architect does require a storeId. This is because of the inconsistencies between frameworks and when you use MVC vs not.

    I've created a story to look into what we can do in Architect, to improve support for this style of application.

    Apologies for my rushed posts. I'll keep your comments in mind.
    Phil Strong
    @philstrong
    #SenchaArchitect
    Sencha Architect Development Team

  6. #6
    Sencha Premium Member
    Join Date
    Jul 2012
    Posts
    105
    Vote Rating
    32
    jptrainor will become famous soon enough jptrainor will become famous soon enough

      0  

    Default


    me three

    I hit this limitation on my first Architect project (which is just something I'm throwing together to learn, not even "real"), hunted for info, and ended up here..

    Unfortunate to hit such fundamental limitations so quickly.

  7. #7
    Sencha - Architect Dev Team Phil.Strong's Avatar
    Join Date
    Mar 2007
    Location
    Olney, MD
    Posts
    1,953
    Vote Rating
    65
    Phil.Strong is just really nice Phil.Strong is just really nice Phil.Strong is just really nice Phil.Strong is just really nice Phil.Strong is just really nice

      0  

    Default


    Views aren't singletons indeed. They are subclasses of the views provided by ExtJS. The problem with views is that they can only be direct subclasses of what ExtJS provides. There is no way to define a subclass of a subclass in Architect unless you save it to the toolbox.
    Follow up here is that with Architect 2.1 you can now in fact subclass your own stuff and not just classes from the framework.
    Phil Strong
    @philstrong
    #SenchaArchitect
    Sencha Architect Development Team

  8. #8
    Sencha Premium Member
    Join Date
    Jul 2012
    Posts
    105
    Vote Rating
    32
    jptrainor will become famous soon enough jptrainor will become famous soon enough

      1  

    Default


    Regarding my comment about the stores limitations..... after having found my way to this thread while hunting down a solution to the single store instance problem I did succeed in coming up with what I find to be a fairly clean solution (although I am totally new to Ext-JS and Architect so I'm not a good judge of what is clean). The magic bullet was:

    1. Create a model as usual.
    2. Create a store backed by a memory proxy. Don't include this store in the top level app store list. this will be the dynamically created store.
    3. Create a the view (call it MyComponent) that will be dynamically created and will reference the dynamically created store (from step 2). Don't include this in the top level app views list.
    4. In a controller event handler add the code to Ext.create your store N times, format your data (per your model definition) and call store.loadData(mydata) to init your stores.
    5. Call Ext.create(MyApp.view.MyComponent, {store: theStore}). i.e. pass the store you just created as a config option. N times, as necessary.
    5. panel.add(theView), or whatever is right for you, N times as necessary.

    That did it form me. Multiple dynamically created view instances each with their own store instance where both the store and view are defined normally using Architect. No override or other tricks or complications necessary.

    I should add, that I came up with that after *much* thrashing around. Too much IMO, but maybe that's just me.

    I have no idea if my solution is optimal, or has problems I have not yet realized.

    It would be good if Architect had some way of permitting a user to flag a store as "dynamic" or "manually instantiated", or similar, and then clearly document how to go about creating it when/where necessary. Standard operating procedure with Architect does not guide one down this path and figuring it out, while one is climbing both the Ext-JS and Architect learning curves, is too painful. Particularly for otherwise experienced developers who know exactly what they want to accomplish and expect this sort of thing to be fairly routine (at least if they were hand coding this).

  9. #9
    Sencha - Architect Dev Team Phil.Strong's Avatar
    Join Date
    Mar 2007
    Location
    Olney, MD
    Posts
    1,953
    Vote Rating
    65
    Phil.Strong is just really nice Phil.Strong is just really nice Phil.Strong is just really nice Phil.Strong is just really nice Phil.Strong is just really nice

      0  

    Default


    @jptrainor thanks for sharing this!

    I would say this is the only way to do what you and the others here are trying to do. Are you changing the storeId or even setting it? Class Name? I see you got around the issue by passing the live store (nice!).

    I don't see any holes here but I'm not running it through any tests other than mentally.

    Others have comments?
    Phil Strong
    @philstrong
    #SenchaArchitect
    Sencha Architect Development Team

  10. #10
    Sencha Premium Member
    Join Date
    Jul 2012
    Posts
    105
    Vote Rating
    32
    jptrainor will become famous soon enough jptrainor will become famous soon enough

      0  

    Default


    re the storeid: I experimented and it appears to make no difference whether the store id has a value or not. In fact, in Architect I cannot seem to clear it anyways. I found the storeid in my "dynamic" store was set to one " " (space) which tells me that I tried to clear it and didn't realize it wasn't actually cleared. Anyways... I gave it a proper value and it made no difference.