Titanium JIRA Archive
Alloy (ALOY)

[ALOY-603] Allow Alloy widgets to be wrapped around child elements in XML views

GitHub Issuen/a
TypeImprovement
PriorityMedium
StatusClosed
ResolutionFixed
Resolution Date2014-08-29T09:09:54.000+0000
Affected Version/sn/a
Fix Version/sAlloy 1.3.0, 2013 Sprint 22
ComponentsXML
Labelsalloy, notable, qe-automatedtest, qe-manualtest, views, widgets, xml
ReporterFokke Zandbergen
AssigneeTony Lukasavage
Created2013-03-16T12:24:35.000+0000
Updated2014-09-02T23:14:35.000+0000

Description

update (10/25/2013)

This has been resolved in a way different than the original description. It is implemented in the example found here: https://github.com/appcelerator/alloy/tree/master/test/apps/advanced/require_children In brief, any child elements of or elements will be passed to that widget's controller as an array, and it will be contained in args.children. Here's a trivial example using , but it works exactly the same for as well:

index.xml

<Alloy>
  <Window>
    <Require src="someRequire">
      <Label>child label</Label>
    </Require>
  </Window>
</Alloy>

someRequire.xml

<Alloy>
  <View id="content"/>
</Alloy>

someRequire.js

var args = arguments[0] || {},

    // args.children contains the elements under the <Require> elements, if any
    children = args.children || [];

// add child views to content
_.each(children, function(child) {
  $.content.add(child);
});

original

Following the discussion at https://groups.google.com/d/msg/appc-ti-alloy/8PVVSE1UzXE/x6frOeTZGd4J I propose to add support for child elements in <Widget></Widget> elements in Alloy XML views. The purpose of this would be to get a reference of these elements from within a widget that doesn't return a view of it's own, but is designed to act upon others. It would function in a way not that different from the existing support for getting a reference of the Widget parent element using this.parent. *Example XML View*
<Alloy>
  <Window id="myWindow">
    <Widget id="myWidget" scr="my.alloy.widget">
      <TableView id="myTable">
        <TableViewRow title="my row" />
      </TableView>
    </Widget>
  </Window>
</Alloy>
*Would be compiled to*
...
$.myWidget = Alloy.createWidget("my.alloy.widget", "widget", {
  id: "myWidget"
});
$.myWidget.setParent($.__views.myWindow);
$.myWidget.setChildren([$.__views.myTable]);
...
*Notes* Since the widget does not provide a view it's stored in $.ID instead of $.__views.ID. Because the widget could contain multiple child elements the methods is setChildren and it accepts an array.

Attachments

FileDateSize
Screen Shot 2013-10-25 at 4.19.39 PM.png2013-10-25T20:35:20.000+000036179
Screen Shot 2013-10-25 at 4.19.47 PM.png2013-10-25T20:35:20.000+000075036

Comments

  1. Davide Cassenti 2013-04-17

    Is there any progress about this?
  2. Tony Lukasavage 2013-04-17

    No, not at this time. There's a number of high priority tickets I need to get to before I'll be able to get back to this one. I don't have a reliable ETA for it yet.
  3. Fokke Zandbergen 2013-07-21

    Huh? How come Pedro is now the reporter? I thought I was.. Anyway, another use case I would like to use this for is:
       <Alloy>
         <Window id="container">
           <Widget src="NavigationGroup">
             <Window id="primary">
               <Label>Hello World</Label>
             </Window>
           </Widget>
         </Window>
       </Alloy>
       
    The widget would return a Ti.UI.iPhone.NavigationGroup on iOS, while just open Window#primary on other platforms, so you have a cross platform solution. Additionally, both the iOS and other implementation could add additional methods for closing the last window or close all but the first.
  4. Fokke Zandbergen 2013-07-21

    Same is true for <Require />. A sample use case would be to have a view/controller that is used in multiple other views to wrap their content in a custom popup, without having to repeat the same view elements in every of these views: View using the wrapper:
       <Alloy>
         <Require="snippets/popup">
           <Label>Hello world</Label>
         </Require>
       </Alloy>
       
    View of the wrapper:
       <Alloy>
         <Window>
           <ImageView image="x.png" onClick="closeDialog" />
           <View id="content" borderSize="10" borderColor="black" height="Ti.UI.SIZE" left="10" right="10">
             
           </View>
         </Window>
       </Alloy>
       
    Controller of the wrapper:
       function closeDialog() {
         $.getView().close();
       }
       
       exports.add = $.content.add;
       
    The above controller code also shows that the controller should expose an add method that receives the first level of wrapped view(s) so it can consume them in whatever way it needs to.
  5. Tony Lukasavage 2013-07-22

    [~fokke] pedro probably moved it from TC to ALOY, and sometimes that inadvertantly reassigns the reporter. I fixed it.
  6. Ronald Treur 2013-07-23

    Thanks again Fokke for bringing this up! I'm very happy to see it will be included in the near future. I originally wanted to wrap the Ti.UI.Window in a widget, but had to reside to windows registering themselves with a custom manager upon creation. This fix/feature will make sure use-cases like this one will utilize the full potential of Alloy's XML Views. Kudos to all involved!
  7. Fokke Zandbergen 2013-07-27

    It seems to work for me by changing just a few lines: Alloy.Require.js#26
           //U.die('<Require> elements may not have child elements.');
       
    Alloy.Require.js#122
            symbolic: args.symbol,
            symbol: args.symbol + '.getViewEx({recurse:true})'
       
    default.js#98
            code += (args.parent.symbolic || args.parent.symbol) + ".add(" + args.symbol + ");\n";
       
    I'm sure there are things to take care off, but this will expect an add method to be exposed by the Widget/Controller, which could then do whatever it wants with the added child view(s).
  8. Tony Lukasavage 2013-08-07

    I'm starting to think about this one, and I think I want to put all the effort onto the widget developer to determine what is done with the children. I don't think a new add() API needs to be introduced for the requires/widgets, it should be the responsibility of the widget designer to handle them. here's a very basic gist of how I would imagine you would implement this behavior, assuming that Alloy provided a "children" argument to widgets/requires: https://gist.github.com/tonylukasavage/6178871 I'd like to keep the implementation simple to see what particular use cases rise up around it. In the future we could designate an XML attribute on or in the widget that identifies the "container" component so that you don't need to assemble the view hierarchy programmatically, but I think this is a good first step and that type of functionality can easily be added later if this proves useful. Thoughts?
  9. Fokke Zandbergen 2013-08-08

    Looks pretty solid, you could even support doing stuff like this:
       <Alloy>
         <Window>
           <Widget src="myWidget">
             <SomeProxy>
               <Button>Hi</Button>
             </SomeProxy>
             <AnotherProxy>
               <Button>One</Button>
               <Button>Two</Button>
             </AnotherProxy>
             <Button>Root</Button>
           </Widget>
         </Window>
       </Alloy>
       
    To be passed as:
       children: {
         SomeProxy: {
           children: [
             [object Ti.UI.Button]
           ]
         },
         AnotherProxy: {
           children: [
             [object Ti.UI.Button],
             [object Ti.UI.Button],
           ]
         },
         children: [
           [object Ti.UI.Button]
         ]
       }
       
    This might seem like a bit too much, but imagine having a widget taking a table, a view for the Pull to Refresh, another for the Infinite Scroll.
  10. Ronald Treur 2013-08-08

    Looks like a very flexible solution to me, I like it!
  11. Tony Lukasavage 2013-10-25

    PR: https://github.com/appcelerator/alloy/pull/258 test app: https://github.com/appcelerator/alloy/tree/master/test/apps/advanced/require_children Functional test should include the following for all supported platforms:

    Run the app

    Ensure that no compile time or runtime errors occur

    Ensure that the resulting UI is composed of the child elements contained in the and elements in the app

    For reference, the iOS 7 screens should look like the attached screenshots (ignore the missing tab titles, its a result of TIMOB-15581)

    All jake test:all tests should pass as well.
  12. Fokke Zandbergen 2013-11-21

  13. Tony Lukasavage 2013-11-21

    [~fokke] I think a new ticket that better details the format and expected behavior would be appropriate. I'm a little foggy on what you are trying to do there, if only because I think you are using the word "proxy" differently than we typically use it. If you do create a ticket, mention this one and I'll make sure they get linked.
  14. Fokke Zandbergen 2013-11-22

    [~tlukasavage] here it is: TC-3318
  15. Federico Casali 2013-12-03

    Verified fixed. TiSDK 3.2.0.v20131127194046 CLI 3.2.0-beta Alloy 1.3.0-beta Titanium Studio 3.2.0.201311262027 iPad OS 7 and simulator Android Google Nexus Galaxy 4.3 MobileWeb (for sample #2) Closing.
  16. Ingo Muschenetz 2014-08-28

    [~fcasali] should this be closed?
  17. Fokke Zandbergen 2014-08-29

    Yes
  18. Federico Casali 2014-09-02

    Yes, it should. Closing.

JSON Source