Chapter One: How to manage the updating area
Hello, After different discussions already listed by Taher [1-9], Leila, Nicolas and me tried another approach. Instead of analyzing how to implement different functionalities offered by modern js framework, we did analyzed how end user use, in general, OFBiz and where we, as an integrator, waste more time to create a screen. To help on this huge task, we set some basic rules : * Work only on screens supported by the theme, defined mainly in xml * This concerns only screens used for back-office applications, oriented to manage data * A developer does not have to know all of js language (or other) but can concentrate on the process/view with the end user to manage a data After a first brainstorm, we have identified three major cases : 1. Navigation and data display 2. View event result (data modification, calculation service, ...) 3. Update an area to refresh data (after data modification) Case 1 and 2 are easy and currently managed by OFBiz (and missing stuff will be simple to add), we concentrate our attention on case 3. To update an area, we follow this pattern 1. We start from a context that display different information 2. That context display a submit form, use a link or another mechanism to call an OFBiz event 3. After receiving the event return, we refresh the desired area with parameters that can come from origin context or from event return. Currently with the screen widget, we can use within a form the element `<on-event-update-area event-type="submit" area-id="" area-target=""/>`. The problem with this use, is that your form needs to know the origin context, to identify what are the areas to update and what are the target to use for the refresh. So your form needs to know where it comes from, what information need to be updated in OFBiz and what will be updated after. This increases complexity for the developer in the way that current form implementation manages : * the data and target to communicate with the server * the behaviour (refreshment) to apply when receiving server response. Example : <form name="EditPartyRoleCustomScreen" type="single" target="createPartyRole"> <field name="partyId"><hidden/></field> <field name="roleTypeId">... <on-event-update-area event-type="submit" area-id="PartyRoles_area" area-target="PartyRolesCustom"> <parameter param-name="partyId" from-field="parameters.partyId"/> </on-event-update-area> </form> If you want to reuse the same form, you need to create another screen with a new form to redefine the on-event-update-area (for instance create a PartyRole). We change the thinking, because since it is the starting context that better knows itself, it's the starting context that will realize the updating operation. The starting context is the screen/menu that call this form. In general a form is contained in a screen (classic) that is called through a link. So we move the idea on this link : <link target="CreatePartyRole" link-type="layered-modal"> <parameter param-name="partyId" from-field="customerParty.partyId"/> <update-area area-target="ResumeInfoCustomer" area-id="xxx"> <parameter param-name="partyId" from-field="customerParty.partyId"/> </update-area> </link> And the form : <form name="EditPartyRole" type="single" target="createPartyRole"> <field name="partyId"><hidden/></field> <field name="roleTypeId">... </form> With this logic you can define a new usage of createPartyRole without redefining a form just : <link target="CreatePartyRole" link-type="layered-modal"> <parameter param-name="partyId" from-field="partyRelationship.partyIdTo"/> <update-area area-target="MyRelationAndDetail" area-id="xxx"> <parameter param-name="partyId" from-field="partyRelationship.partyIdTo"/> <parameter param-name="partyRelationTypeId" value="IRL_LIKE"/> </update-area> </link> After some use we identified as pro and con feedback : * updating form is reusable and contains only code related to the form action * link being in origin context, the developer knows where he is and where he wants to go * Menu oriented management offers a quick vision on how the screen will works * update-area seems to be a too technical name * we always have to manage area to update manually * too many areas to update become a headache and not only for the developer We did not explain how we have done it, to try to focus the discussion on the principles. It would be a pleasure to have some criticism of this approach, and we would try, in a second chapter to introduce other concepts that appeared after the screens were made more dynamic and others to lowers the identified cons. Thanks, The Néréide Team [1] https://s.apache.org/rf94 [2] https://s.apache.org/g5zr [3] https://s.apache.org/XpBO [4] https://s.apache.org/YIL1 [5] https://s.apache.org/836D [6] https://s.apache.org/DhyB [7] https://s.apache.org/Lv9E [8] https://s.apache.org/zKIo [9] https://s.apache.org/D6jx |
Hello Gil,
Great research on the subject, thank you for sharing. I could be wrong here, but at a first glance it seems you want to essentially create a tag "<update-area ..." which essentially renders another screen dynamically upon clicking / activating the URL. If my understanding is correct, then most likely they way you want to implement this is probably some web request to the backend which renders back a partial screen that you insert into the DOM right? If what I describe above is close to your idea, then I think the implementation might be relying on the server to do the work of painting instead of relying on the browser to do the heavy lifting. This also only works with one widget, which is the URL widget as opposed to having a general purpose dynamic behavior in the system (assuming this is desired). However, having a general purpose dynamic behavior means we need a method to bind variables to values at the front end without consulting the back-end. This reduces the load on the server and provides a faster / richer experience to the user. But it would be too painful to rely on plain javascript or jQuery to achieve such a result which is the reason why frameworks like React, Vue, and others emerged as modern SPA frameworks. Adopting an SPA framework would provide dynamic behavior (everywhere) instead of certain widgets, and it can be expanded to even include page navigation and whatnot. Of course this is more work than what you're suggesting here. but if we continue with such small improvements, you might end up having lots of javascript (maybe that's already the case) which might increase the difficulty of adopting an SPA framework in the future. So it comes down to this question (which I don't necessarily have an answer to): Do you want an SPA framework now or in the future, or do you want to continue with status quo into the future? If you want an SPA framework, then we should minimize the usage of custom javascript everywhere and adopt a framework that completely replaces all the javascript that currently exists for all the widgets. If not, then we can proceed with your proposition and any others in the future knowing that an overhaul is not needed. Cheers, Taher Alkhateeb On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne <[hidden email]> wrote: > > Chapter One: How to manage the updating area > > Hello, > > After different discussions already listed by Taher [1-9], Leila, > Nicolas and me tried another approach. > Instead of analyzing how to implement different functionalities offered > by modern js framework, we did analyzed how end user use, in general, > OFBiz and where we, as an integrator, waste more time to create a > screen. > > To help on this huge task, we set some basic rules : > * Work only on screens supported by the theme, defined mainly in xml > * This concerns only screens used for back-office applications, > oriented to manage data > * A developer does not have to know all of js language (or other) > but can concentrate on the process/view with the end user to > manage a data > > > After a first brainstorm, we have identified three major cases : > 1. Navigation and data display > 2. View event result (data modification, calculation service, ...) > 3. Update an area to refresh data (after data modification) > > Case 1 and 2 are easy and currently managed by OFBiz (and missing stuff > will be simple to add), we concentrate our attention on case 3. > > To update an area, we follow this pattern > > 1. We start from a context that display different information > > 2. That context display a submit form, use a link or another > mechanism to call an OFBiz event > > 3. After receiving the event return, we refresh the desired area > with parameters that can come from origin context or from event > return. > > > Currently with the screen widget, we can use within a form the element > `<on-event-update-area event-type="submit" area-id="" area-target=""/>`. > > The problem with this use, is that your form needs to know the origin > context, to identify what are the areas to update and what are the > target to use for the refresh. > > So your form needs to know where it comes from, what information need to > be updated in OFBiz and what will be updated after. > > This increases complexity for the developer in the way that current form > implementation manages : > * the data and target to communicate with the server > * the behaviour (refreshment) to apply when receiving server response. > > Example : > <form name="EditPartyRoleCustomScreen" type="single" target="createPartyRole"> > <field name="partyId"><hidden/></field> > <field name="roleTypeId">... > <on-event-update-area event-type="submit" area-id="PartyRoles_area" > area-target="PartyRolesCustom"> > <parameter param-name="partyId" from-field="parameters.partyId"/> > </on-event-update-area> > </form> > > If you want to reuse the same form, you need to create another screen > with a new form to redefine the on-event-update-area (for instance > create a PartyRole). > > We change the thinking, because since it is the starting context that > better knows itself, it's the starting context that will realize the > updating operation. The starting context is the screen/menu that call > this form. > > In general a form is contained in a screen (classic) that is called > through a link. So we move the idea on this link : > > <link target="CreatePartyRole" link-type="layered-modal"> > <parameter param-name="partyId" from-field="customerParty.partyId"/> > <update-area area-target="ResumeInfoCustomer" area-id="xxx"> > <parameter param-name="partyId" from-field="customerParty.partyId"/> > </update-area> > </link> > > And the form : > > <form name="EditPartyRole" type="single" target="createPartyRole"> > <field name="partyId"><hidden/></field> > <field name="roleTypeId">... > </form> > > With this logic you can define a new usage of createPartyRole > without redefining a form just : > > <link target="CreatePartyRole" link-type="layered-modal"> > <parameter param-name="partyId" from-field="partyRelationship.partyIdTo"/> > <update-area area-target="MyRelationAndDetail" area-id="xxx"> > <parameter param-name="partyId" from-field="partyRelationship.partyIdTo"/> > <parameter param-name="partyRelationTypeId" value="IRL_LIKE"/> > </update-area> > </link> > > After some use we identified as pro and con feedback : > * updating form is reusable and contains only code related to the > form action > * link being in origin context, the developer knows where he is and > where he wants to go > * Menu oriented management offers a quick vision on how the screen will works > > * update-area seems to be a too technical name > * we always have to manage area to update manually > * too many areas to update become a headache and not only for the developer > > We did not explain how we have done it, to try to focus the discussion > on the principles. > > It would be a pleasure to have some criticism of this approach, and we > would try, in a second chapter to introduce other concepts that appeared > after the screens were made more dynamic and others to lowers the > identified cons. > > Thanks, > > The Néréide Team > > [1] https://s.apache.org/rf94 > [2] https://s.apache.org/g5zr > [3] https://s.apache.org/XpBO > [4] https://s.apache.org/YIL1 > [5] https://s.apache.org/836D > [6] https://s.apache.org/DhyB > [7] https://s.apache.org/Lv9E > [8] https://s.apache.org/zKIo > [9] https://s.apache.org/D6jx > |
In reply to this post by Gil Portenseigne
Hello Gil, (and Néréide Team)
Thank you for sharing research and formal process to be concentrated on concept first. just short remarks inline Le 13/12/2019 à 16:52, Gil Portenseigne a écrit : > Chapter One: How to manage the updating area > > Hello, > > After different discussions already listed by Taher [1-9], Leila, > Nicolas and me tried another approach. > Instead of analyzing how to implement different functionalities offered > by modern js framework, we did analyzed how end user use, in general, > OFBiz and where we, as an integrator, waste more time to create a > screen. > > To help on this huge task, we set some basic rules : > * Work only on screens supported by the theme, defined mainly in xml > * This concerns only screens used for back-office applications, > oriented to manage data > * A developer does not have to know all of js language (or other) > but can concentrate on the process/view with the end user to > manage a data > > > After a first brainstorm, we have identified three major cases : > 1. Navigation and data display > 2. View event result (data modification, calculation service, ...) > 3. Update an area to refresh data (after data modification) > > Case 1 and 2 are easy and currently managed by OFBiz (and missing stuff > will be simple to add), we concentrate our attention on case 3. there are still some point to study for 1 and 2, but one point by one point is a good approach > > To update an area, we follow this pattern > > 1. We start from a context that display different information > > 2. That context display a submit form, use a link or another > mechanism to call an OFBiz event > > 3. After receiving the event return, we refresh the desired area > with parameters that can come from origin context or from event > return. > > > Currently with the screen widget, we can use within a form the element > `<on-event-update-area event-type="submit" area-id="" area-target=""/>`. > > The problem with this use, is that your form needs to know the origin > context, to identify what are the areas to update and what are the > target to use for the refresh. > > So your form needs to know where it comes from, what information need to > be updated in OFBiz and what will be updated after. > > This increases complexity for the developer in the way that current form > implementation manages : > * the data and target to communicate with the server > * the behaviour (refreshment) to apply when receiving server response. > > Example : > <form name="EditPartyRoleCustomScreen" type="single" target="createPartyRole"> > <field name="partyId"><hidden/></field> > <field name="roleTypeId">... > <on-event-update-area event-type="submit" area-id="PartyRoles_area" > area-target="PartyRolesCustom"> > <parameter param-name="partyId" from-field="parameters.partyId"/> > </on-event-update-area> > </form> > > If you want to reuse the same form, you need to create another screen > with a new form to redefine the on-event-update-area (for instance > create a PartyRole). > > We change the thinking, because since it is the starting context that > better knows itself, it's the starting context that will realize the > updating operation. The starting context is the screen/menu that call > this form. > > In general a form is contained in a screen (classic) that is called > through a link. So we move the idea on this link : > > <link target="CreatePartyRole" link-type="layered-modal"> > <parameter param-name="partyId" from-field="customerParty.partyId"/> > <update-area area-target="ResumeInfoCustomer" area-id="xxx"> > <parameter param-name="partyId" from-field="customerParty.partyId"/> > </update-area> > </link> > > And the form : > > <form name="EditPartyRole" type="single" target="createPartyRole"> > <field name="partyId"><hidden/></field> > <field name="roleTypeId">... > </form> > > With this logic you can define a new usage of createPartyRole > without redefining a form just : > > <link target="CreatePartyRole" link-type="layered-modal"> > <parameter param-name="partyId" from-field="partyRelationship.partyIdTo"/> > <update-area area-target="MyRelationAndDetail" area-id="xxx"> > <parameter param-name="partyId" from-field="partyRelationship.partyIdTo"/> > <parameter param-name="partyRelationTypeId" value="IRL_LIKE"/> > </update-area> > </link> > > After some use we identified as pro and con feedback : > * updating form is reusable and contains only code related to the > form action > * link being in origin context, the developer knows where he is and > where he wants to go +1 > * Menu oriented management offers a quick vision on how the screen will works +1 > > * update-area seems to be a too technical name 0 because name seem clear > * we always have to manage area to update manually +1 UI is area management and their content Other case is sometime area area watching event to update themself > * too many areas to update become a headache and not only for the developer +1 > > We did not explain how we have done it, to try to focus the discussion > on the principles. > > It would be a pleasure to have some criticism of this approach, and we > would try, in a second chapter to introduce other concepts that appeared > after the screens were made more dynamic and others to lowers the > identified cons. In the POC-Vuejs we have started working on similar idea (using logical field name for area and field value send by the caller) but not at this concept level and your approach is very clear (and good) to be able to be implemented after the and of the discussion. It will be simple to implement it when it it will be time. Thank you. > > Thanks, > > The Néréide Team > > [1] https://s.apache.org/rf94 > [2] https://s.apache.org/g5zr > [3] https://s.apache.org/XpBO > [4] https://s.apache.org/YIL1 > [5] https://s.apache.org/836D > [6] https://s.apache.org/DhyB > [7] https://s.apache.org/Lv9E > [8] https://s.apache.org/zKIo > [9] https://s.apache.org/D6jx > |
In reply to this post by taher
Hello Taher,
> Do you want an SPA framework now or in the future, is a very important question but which road to use to go is important too. As with the current gui renderer architecture, it's possible to have multiple rendrer engine for the "same" screen/menu/form xml files, one question is : is it clever to have same functionality with the multiple renderer ? maybe the html should be oriented low-technology approach, and so no javascript or minimum (in futur) the SPA should oriented multi-device and "modern" approach In all case evolution can be step by step and having clear xml formal expression for user interaction is good. With POC-VueJs we wanted to answerd to the question : is it possible to have screen/menu/form xml files AND SPA renderer with all advantage of SPA. Currently, answer is clearly Yes. Our choices or codes are maybe not correct but it's not with a lot of workaround to be able to say it works. Some value are bind on the front end and when back-end is consulted, value in front end are updated and so screen are updated. (one more time, our code is only a demonstration code to help to find the goods one) 80-20 rule is always true, with SPA too so I'm really confident than 80% of xml screen/menu/form can be renderer with a SPA and having a very good SPA advantage usage. For the 20%, it will need to have dedicated SPA component, and during "migration" process which screen should be in 20% will be discuss. Olivier Le 14/12/2019 à 17:51, Taher Alkhateeb a écrit : > Hello Gil, > > Great research on the subject, thank you for sharing. > > I could be wrong here, but at a first glance it seems you want to > essentially create a tag "<update-area ..." which essentially renders > another screen dynamically upon clicking / activating the URL. If my > understanding is correct, then most likely they way you want to > implement this is probably some web request to the backend which > renders back a partial screen that you insert into the DOM right? > > If what I describe above is close to your idea, then I think the > implementation might be relying on the server to do the work of > painting instead of relying on the browser to do the heavy lifting. > This also only works with one widget, which is the URL widget as > opposed to having a general purpose dynamic behavior in the system > (assuming this is desired). > > However, having a general purpose dynamic behavior means we need a > method to bind variables to values at the front end without consulting > the back-end. This reduces the load on the server and provides a > faster / richer experience to the user. But it would be too painful to > rely on plain javascript or jQuery to achieve such a result which is > the reason why frameworks like React, Vue, and others emerged as > modern SPA frameworks. Adopting an SPA framework would provide dynamic > behavior (everywhere) instead of certain widgets, and it can be > expanded to even include page navigation and whatnot. Of course this > is more work than what you're suggesting here. but if we continue with > such small improvements, you might end up having lots of javascript > (maybe that's already the case) which might increase the difficulty of > adopting an SPA framework in the future. > > So it comes down to this question (which I don't necessarily have an answer to): > > Do you want an SPA framework now or in the future, or do you want to > continue with status quo into the future? If you want an SPA > framework, then we should minimize the usage of custom javascript > everywhere and adopt a framework that completely replaces all the > javascript that currently exists for all the widgets. If not, then we > can proceed with your proposition and any others in the future knowing > that an overhaul is not needed. > > Cheers, > > Taher Alkhateeb > > On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne > <[hidden email]> wrote: >> >> Chapter One: How to manage the updating area >> >> Hello, >> >> After different discussions already listed by Taher [1-9], Leila, >> Nicolas and me tried another approach. >> Instead of analyzing how to implement different functionalities offered >> by modern js framework, we did analyzed how end user use, in general, >> OFBiz and where we, as an integrator, waste more time to create a >> screen. >> >> To help on this huge task, we set some basic rules : >> * Work only on screens supported by the theme, defined mainly in xml >> * This concerns only screens used for back-office applications, >> oriented to manage data >> * A developer does not have to know all of js language (or other) >> but can concentrate on the process/view with the end user to >> manage a data >> >> >> After a first brainstorm, we have identified three major cases : >> 1. Navigation and data display >> 2. View event result (data modification, calculation service, ...) >> 3. Update an area to refresh data (after data modification) >> >> Case 1 and 2 are easy and currently managed by OFBiz (and missing stuff >> will be simple to add), we concentrate our attention on case 3. >> >> To update an area, we follow this pattern >> >> 1. We start from a context that display different information >> >> 2. That context display a submit form, use a link or another >> mechanism to call an OFBiz event >> >> 3. After receiving the event return, we refresh the desired area >> with parameters that can come from origin context or from event >> return. >> >> >> Currently with the screen widget, we can use within a form the element >> `<on-event-update-area event-type="submit" area-id="" area-target=""/>`. >> >> The problem with this use, is that your form needs to know the origin >> context, to identify what are the areas to update and what are the >> target to use for the refresh. >> >> So your form needs to know where it comes from, what information need to >> be updated in OFBiz and what will be updated after. >> >> This increases complexity for the developer in the way that current form >> implementation manages : >> * the data and target to communicate with the server >> * the behaviour (refreshment) to apply when receiving server response. >> >> Example : >> <form name="EditPartyRoleCustomScreen" type="single" target="createPartyRole"> >> <field name="partyId"><hidden/></field> >> <field name="roleTypeId">... >> <on-event-update-area event-type="submit" area-id="PartyRoles_area" >> area-target="PartyRolesCustom"> >> <parameter param-name="partyId" from-field="parameters.partyId"/> >> </on-event-update-area> >> </form> >> >> If you want to reuse the same form, you need to create another screen >> with a new form to redefine the on-event-update-area (for instance >> create a PartyRole). >> >> We change the thinking, because since it is the starting context that >> better knows itself, it's the starting context that will realize the >> updating operation. The starting context is the screen/menu that call >> this form. >> >> In general a form is contained in a screen (classic) that is called >> through a link. So we move the idea on this link : >> >> <link target="CreatePartyRole" link-type="layered-modal"> >> <parameter param-name="partyId" from-field="customerParty.partyId"/> >> <update-area area-target="ResumeInfoCustomer" area-id="xxx"> >> <parameter param-name="partyId" from-field="customerParty.partyId"/> >> </update-area> >> </link> >> >> And the form : >> >> <form name="EditPartyRole" type="single" target="createPartyRole"> >> <field name="partyId"><hidden/></field> >> <field name="roleTypeId">... >> </form> >> >> With this logic you can define a new usage of createPartyRole >> without redefining a form just : >> >> <link target="CreatePartyRole" link-type="layered-modal"> >> <parameter param-name="partyId" from-field="partyRelationship.partyIdTo"/> >> <update-area area-target="MyRelationAndDetail" area-id="xxx"> >> <parameter param-name="partyId" from-field="partyRelationship.partyIdTo"/> >> <parameter param-name="partyRelationTypeId" value="IRL_LIKE"/> >> </update-area> >> </link> >> >> After some use we identified as pro and con feedback : >> * updating form is reusable and contains only code related to the >> form action >> * link being in origin context, the developer knows where he is and >> where he wants to go >> * Menu oriented management offers a quick vision on how the screen will works >> >> * update-area seems to be a too technical name >> * we always have to manage area to update manually >> * too many areas to update become a headache and not only for the developer >> >> We did not explain how we have done it, to try to focus the discussion >> on the principles. >> >> It would be a pleasure to have some criticism of this approach, and we >> would try, in a second chapter to introduce other concepts that appeared >> after the screens were made more dynamic and others to lowers the >> identified cons. >> >> Thanks, >> >> The Néréide Team >> >> [1] https://s.apache.org/rf94 >> [2] https://s.apache.org/g5zr >> [3] https://s.apache.org/XpBO >> [4] https://s.apache.org/YIL1 >> [5] https://s.apache.org/836D >> [6] https://s.apache.org/DhyB >> [7] https://s.apache.org/Lv9E >> [8] https://s.apache.org/zKIo >> [9] https://s.apache.org/D6jx >> |
In reply to this post by taher
Hi Taher
I've been using Angular for custom apps over the past year. This is my approach: 1. Ofbiz deployed as an AppServer: 1.1 Ofbiz controller resolves API request calls; 1.2 Ofbiz Service Engine executes Services; 1.3 Entity Engine for persistence; 1.4 Returns JSON object - including Ofbiz context;; 1.5 Ofbiz Forms used for additional business logic, fields etc; 1.6 Ofbiz Screens not used at all. 2. Angular (On Apache HTTPD or Ionic/Cordova/JQueryMobile or even JAVAFX(haven't tried this, but it's possible)): 2.1 Typescripting types for Ofbiz entities used; 2.2 Angular services for API calls corresponding to controller request-mappings; 2.3 Dynamic Angular Forms - based on Ofbiz Form defs; 2.4 Other static content; 3. Authentication 3.1 With JWT; 3.2 Sessionless & no cookies; 3.3 Ofbiz LoginWorker & Permission Engine for authorization; The big takeaway here is that Ofbiz Screens aren't used at all. Ofbiz Forms are used to set fields, execute services and deal with issues like locale etc. Cheers gavin On Sat, Dec 14, 2019 at 6:52 PM Taher Alkhateeb <[hidden email]> wrote: > Hello Gil, > > Great research on the subject, thank you for sharing. > > I could be wrong here, but at a first glance it seems you want to > essentially create a tag "<update-area ..." which essentially renders > another screen dynamically upon clicking / activating the URL. If my > understanding is correct, then most likely they way you want to > implement this is probably some web request to the backend which > renders back a partial screen that you insert into the DOM right? > > If what I describe above is close to your idea, then I think the > implementation might be relying on the server to do the work of > painting instead of relying on the browser to do the heavy lifting. > This also only works with one widget, which is the URL widget as > opposed to having a general purpose dynamic behavior in the system > (assuming this is desired). > > However, having a general purpose dynamic behavior means we need a > method to bind variables to values at the front end without consulting > the back-end. This reduces the load on the server and provides a > faster / richer experience to the user. But it would be too painful to > rely on plain javascript or jQuery to achieve such a result which is > the reason why frameworks like React, Vue, and others emerged as > modern SPA frameworks. Adopting an SPA framework would provide dynamic > behavior (everywhere) instead of certain widgets, and it can be > expanded to even include page navigation and whatnot. Of course this > is more work than what you're suggesting here. but if we continue with > such small improvements, you might end up having lots of javascript > (maybe that's already the case) which might increase the difficulty of > adopting an SPA framework in the future. > > So it comes down to this question (which I don't necessarily have an > answer to): > > Do you want an SPA framework now or in the future, or do you want to > continue with status quo into the future? If you want an SPA > framework, then we should minimize the usage of custom javascript > everywhere and adopt a framework that completely replaces all the > javascript that currently exists for all the widgets. If not, then we > can proceed with your proposition and any others in the future knowing > that an overhaul is not needed. > > Cheers, > > Taher Alkhateeb > > On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne > <[hidden email]> wrote: > > > > Chapter One: How to manage the updating area > > > > Hello, > > > > After different discussions already listed by Taher [1-9], Leila, > > Nicolas and me tried another approach. > > Instead of analyzing how to implement different functionalities offered > > by modern js framework, we did analyzed how end user use, in general, > > OFBiz and where we, as an integrator, waste more time to create a > > screen. > > > > To help on this huge task, we set some basic rules : > > * Work only on screens supported by the theme, defined mainly in xml > > * This concerns only screens used for back-office applications, > > oriented to manage data > > * A developer does not have to know all of js language (or other) > > but can concentrate on the process/view with the end user to > > manage a data > > > > > > After a first brainstorm, we have identified three major cases : > > 1. Navigation and data display > > 2. View event result (data modification, calculation service, ...) > > 3. Update an area to refresh data (after data modification) > > > > Case 1 and 2 are easy and currently managed by OFBiz (and missing stuff > > will be simple to add), we concentrate our attention on case 3. > > > > To update an area, we follow this pattern > > > > 1. We start from a context that display different information > > > > 2. That context display a submit form, use a link or another > > mechanism to call an OFBiz event > > > > 3. After receiving the event return, we refresh the desired area > > with parameters that can come from origin context or from event > > return. > > > > > > Currently with the screen widget, we can use within a form the element > > `<on-event-update-area event-type="submit" area-id="" area-target=""/>`. > > > > The problem with this use, is that your form needs to know the origin > > context, to identify what are the areas to update and what are the > > target to use for the refresh. > > > > So your form needs to know where it comes from, what information need to > > be updated in OFBiz and what will be updated after. > > > > This increases complexity for the developer in the way that current form > > implementation manages : > > * the data and target to communicate with the server > > * the behaviour (refreshment) to apply when receiving server response. > > > > Example : > > <form name="EditPartyRoleCustomScreen" type="single" > target="createPartyRole"> > > <field name="partyId"><hidden/></field> > > <field name="roleTypeId">... > > <on-event-update-area event-type="submit" > area-id="PartyRoles_area" > > area-target="PartyRolesCustom"> > > <parameter param-name="partyId" > from-field="parameters.partyId"/> > > </on-event-update-area> > > </form> > > > > If you want to reuse the same form, you need to create another screen > > with a new form to redefine the on-event-update-area (for instance > > create a PartyRole). > > > > We change the thinking, because since it is the starting context that > > better knows itself, it's the starting context that will realize the > > updating operation. The starting context is the screen/menu that call > > this form. > > > > In general a form is contained in a screen (classic) that is called > > through a link. So we move the idea on this link : > > > > <link target="CreatePartyRole" link-type="layered-modal"> > > <parameter param-name="partyId" > from-field="customerParty.partyId"/> > > <update-area area-target="ResumeInfoCustomer" > area-id="xxx"> > > <parameter param-name="partyId" > from-field="customerParty.partyId"/> > > </update-area> > > </link> > > > > And the form : > > > > <form name="EditPartyRole" type="single" > target="createPartyRole"> > > <field name="partyId"><hidden/></field> > > <field name="roleTypeId">... > > </form> > > > > With this logic you can define a new usage of createPartyRole > > without redefining a form just : > > > > <link target="CreatePartyRole" link-type="layered-modal"> > > <parameter param-name="partyId" > from-field="partyRelationship.partyIdTo"/> > > <update-area area-target="MyRelationAndDetail" > area-id="xxx"> > > <parameter param-name="partyId" > from-field="partyRelationship.partyIdTo"/> > > <parameter param-name="partyRelationTypeId" > value="IRL_LIKE"/> > > </update-area> > > </link> > > > > After some use we identified as pro and con feedback : > > * updating form is reusable and contains only code related to the > > form action > > * link being in origin context, the developer knows where he is and > > where he wants to go > > * Menu oriented management offers a quick vision on how the screen > will works > > > > * update-area seems to be a too technical name > > * we always have to manage area to update manually > > * too many areas to update become a headache and not only for the > developer > > > > We did not explain how we have done it, to try to focus the discussion > > on the principles. > > > > It would be a pleasure to have some criticism of this approach, and we > > would try, in a second chapter to introduce other concepts that appeared > > after the screens were made more dynamic and others to lowers the > > identified cons. > > > > Thanks, > > > > The Néréide Team > > > > [1] https://s.apache.org/rf94 > > [2] https://s.apache.org/g5zr > > [3] https://s.apache.org/XpBO > > [4] https://s.apache.org/YIL1 > > [5] https://s.apache.org/836D > > [6] https://s.apache.org/DhyB > > [7] https://s.apache.org/Lv9E > > [8] https://s.apache.org/zKIo > > [9] https://s.apache.org/D6jx > > > |
In reply to this post by holivier
Hi Oliver
I think separating the GUI completely from the application layer could be an option worthy of exploring. That would mean api requests and with standard responses in JSON or XML. What the end user does with the response is entirely up to him/her. In this scenario the responses and their shapes are highly structured leaving the chosen GUI framework up to the user. Not easy as business/workflow processes would have to be represented by well defined api endpoints. Although the current view renderer accommodates abstraction for different view implementations it only really result in HTML in the end. Your question: is it clever to have same functionality with the multiple renderer? My response: don't have a view renderer at all. What do you think? Gavin On Tue, Dec 17, 2019 at 12:22 PM Olivier Heintz <[hidden email]> wrote: > Hello Taher, > > > Do you want an SPA framework now or in the future, > is a very important question but > which road to use to go is important too. > > As with the current gui renderer architecture, it's possible to have > multiple rendrer engine for the "same" screen/menu/form xml files, > one question is : is it clever to have same functionality with the > multiple renderer ? > maybe the html should be oriented low-technology approach, and so no > javascript or minimum (in futur) > the SPA should oriented multi-device and "modern" approach > > In all case evolution can be step by step and having clear xml formal > expression for user interaction is good. > > With POC-VueJs we wanted to answerd to the question : is it possible to > have screen/menu/form xml files AND SPA renderer with all advantage of SPA. > Currently, answer is clearly Yes. > Our choices or codes are maybe not correct but it's not with a lot of > workaround to be able to say it works. > Some value are bind on the front end and when back-end is consulted, value > in front end are updated and so screen are updated. > (one more time, our code is only a demonstration code to help to find the > goods one) > > 80-20 rule is always true, with SPA too > so I'm really confident than 80% of xml screen/menu/form can be renderer > with a SPA and having a very good SPA advantage usage. > For the 20%, it will need to have dedicated SPA component, and during > "migration" process which screen should be in 20% will be discuss. > > Olivier > > > > Le 14/12/2019 à 17:51, Taher Alkhateeb a écrit : > > Hello Gil, > > > > Great research on the subject, thank you for sharing. > > > > I could be wrong here, but at a first glance it seems you want to > > essentially create a tag "<update-area ..." which essentially renders > > another screen dynamically upon clicking / activating the URL. If my > > understanding is correct, then most likely they way you want to > > implement this is probably some web request to the backend which > > renders back a partial screen that you insert into the DOM right? > > > > If what I describe above is close to your idea, then I think the > > implementation might be relying on the server to do the work of > > painting instead of relying on the browser to do the heavy lifting. > > This also only works with one widget, which is the URL widget as > > opposed to having a general purpose dynamic behavior in the system > > (assuming this is desired). > > > > However, having a general purpose dynamic behavior means we need a > > method to bind variables to values at the front end without consulting > > the back-end. This reduces the load on the server and provides a > > faster / richer experience to the user. But it would be too painful to > > rely on plain javascript or jQuery to achieve such a result which is > > the reason why frameworks like React, Vue, and others emerged as > > modern SPA frameworks. Adopting an SPA framework would provide dynamic > > behavior (everywhere) instead of certain widgets, and it can be > > expanded to even include page navigation and whatnot. Of course this > > is more work than what you're suggesting here. but if we continue with > > such small improvements, you might end up having lots of javascript > > (maybe that's already the case) which might increase the difficulty of > > adopting an SPA framework in the future. > > > > So it comes down to this question (which I don't necessarily have an > answer to): > > > > Do you want an SPA framework now or in the future, or do you want to > > continue with status quo into the future? If you want an SPA > > framework, then we should minimize the usage of custom javascript > > everywhere and adopt a framework that completely replaces all the > > javascript that currently exists for all the widgets. If not, then we > > can proceed with your proposition and any others in the future knowing > > that an overhaul is not needed. > > > > Cheers, > > > > Taher Alkhateeb > > > > On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne > > <[hidden email]> wrote: > >> > >> Chapter One: How to manage the updating area > >> > >> Hello, > >> > >> After different discussions already listed by Taher [1-9], Leila, > >> Nicolas and me tried another approach. > >> Instead of analyzing how to implement different functionalities offered > >> by modern js framework, we did analyzed how end user use, in general, > >> OFBiz and where we, as an integrator, waste more time to create a > >> screen. > >> > >> To help on this huge task, we set some basic rules : > >> * Work only on screens supported by the theme, defined mainly in xml > >> * This concerns only screens used for back-office applications, > >> oriented to manage data > >> * A developer does not have to know all of js language (or other) > >> but can concentrate on the process/view with the end user to > >> manage a data > >> > >> > >> After a first brainstorm, we have identified three major cases : > >> 1. Navigation and data display > >> 2. View event result (data modification, calculation service, ...) > >> 3. Update an area to refresh data (after data modification) > >> > >> Case 1 and 2 are easy and currently managed by OFBiz (and missing stuff > >> will be simple to add), we concentrate our attention on case 3. > >> > >> To update an area, we follow this pattern > >> > >> 1. We start from a context that display different information > >> > >> 2. That context display a submit form, use a link or another > >> mechanism to call an OFBiz event > >> > >> 3. After receiving the event return, we refresh the desired area > >> with parameters that can come from origin context or from event > >> return. > >> > >> > >> Currently with the screen widget, we can use within a form the element > >> `<on-event-update-area event-type="submit" area-id="" area-target=""/>`. > >> > >> The problem with this use, is that your form needs to know the origin > >> context, to identify what are the areas to update and what are the > >> target to use for the refresh. > >> > >> So your form needs to know where it comes from, what information need to > >> be updated in OFBiz and what will be updated after. > >> > >> This increases complexity for the developer in the way that current form > >> implementation manages : > >> * the data and target to communicate with the server > >> * the behaviour (refreshment) to apply when receiving server response. > >> > >> Example : > >> <form name="EditPartyRoleCustomScreen" type="single" > target="createPartyRole"> > >> <field name="partyId"><hidden/></field> > >> <field name="roleTypeId">... > >> <on-event-update-area event-type="submit" > area-id="PartyRoles_area" > >> area-target="PartyRolesCustom"> > >> <parameter param-name="partyId" > from-field="parameters.partyId"/> > >> </on-event-update-area> > >> </form> > >> > >> If you want to reuse the same form, you need to create another screen > >> with a new form to redefine the on-event-update-area (for instance > >> create a PartyRole). > >> > >> We change the thinking, because since it is the starting context that > >> better knows itself, it's the starting context that will realize the > >> updating operation. The starting context is the screen/menu that call > >> this form. > >> > >> In general a form is contained in a screen (classic) that is called > >> through a link. So we move the idea on this link : > >> > >> <link target="CreatePartyRole" link-type="layered-modal"> > >> <parameter param-name="partyId" > from-field="customerParty.partyId"/> > >> <update-area area-target="ResumeInfoCustomer" > area-id="xxx"> > >> <parameter param-name="partyId" > from-field="customerParty.partyId"/> > >> </update-area> > >> </link> > >> > >> And the form : > >> > >> <form name="EditPartyRole" type="single" > target="createPartyRole"> > >> <field name="partyId"><hidden/></field> > >> <field name="roleTypeId">... > >> </form> > >> > >> With this logic you can define a new usage of createPartyRole > >> without redefining a form just : > >> > >> <link target="CreatePartyRole" link-type="layered-modal"> > >> <parameter param-name="partyId" > from-field="partyRelationship.partyIdTo"/> > >> <update-area area-target="MyRelationAndDetail" > area-id="xxx"> > >> <parameter param-name="partyId" > from-field="partyRelationship.partyIdTo"/> > >> <parameter param-name="partyRelationTypeId" > value="IRL_LIKE"/> > >> </update-area> > >> </link> > >> > >> After some use we identified as pro and con feedback : > >> * updating form is reusable and contains only code related to the > >> form action > >> * link being in origin context, the developer knows where he is and > >> where he wants to go > >> * Menu oriented management offers a quick vision on how the screen > will works > >> > >> * update-area seems to be a too technical name > >> * we always have to manage area to update manually > >> * too many areas to update become a headache and not only for the > developer > >> > >> We did not explain how we have done it, to try to focus the discussion > >> on the principles. > >> > >> It would be a pleasure to have some criticism of this approach, and we > >> would try, in a second chapter to introduce other concepts that appeared > >> after the screens were made more dynamic and others to lowers the > >> identified cons. > >> > >> Thanks, > >> > >> The Néréide Team > >> > >> [1] https://s.apache.org/rf94 > >> [2] https://s.apache.org/g5zr > >> [3] https://s.apache.org/XpBO > >> [4] https://s.apache.org/YIL1 > >> [5] https://s.apache.org/836D > >> [6] https://s.apache.org/DhyB > >> [7] https://s.apache.org/Lv9E > >> [8] https://s.apache.org/zKIo > >> [9] https://s.apache.org/D6jx > >> > |
In reply to this post by taher
Hello Taher,
The proposition you saw with your first glance is about : * Intent : describing into a link/menu definition, the way that the dynamically rendered form will refresh the screen upon submission success * Implementation : adding a tag that will generate a refreshment event on submission within the screen that is inserted into the DOM by the augmented link (like a success callback). That is one step of the proposal, but yes i think you got it well. We have to make clear that our intent is not to add lot of new widget augmentations to get dynamic screens. This new tag that should have been named "callback-update-area", would complete the already existing "<on-event-update-area" form feature. Giving more control to the origin screen. For my personal point of view, your point come at the good timing to get considered before going too far. But in fact in our attempts, i feel like we did not go that far to get something working nicely as a first step. So thanks for your feedback, since i am not familiar enough with Single Page Application aka SPA frameworks (in France SPA is the main french Animal Protection Association :-) ) we had a discussion with Samuel and Mathieu to build you a better answer to your question (i.e. if SPA will fit in our effort). Our research is about **screen definition** for back office application, so we are not talking about technology but about screen structure definition concepts. In my opinion SPA (based on screen definitions) is a technical implementation, so it is not part of our prime target. Those structure definition concepts must be well thought enough to be compliant with any technical implementation in theme (based on common-theme). In that vision implementing a theme for SPA application should be possible, but in our opinion a gigantic task to support the screen engine. We think that for back office application, we should stay with the classic way to implement screens, and improve it to get more efficient. For front office, and high expectation back office application, if SPA is to be used, implementing it with a custom theme and freemarker is the simpler way to be efficient. PS: i did signed Néréide Team in my precedent email, but it is not a company initiative, this should have been signed Leila, Nicolas and Gil. Sorry for that. Thanks Gil Le 19:51 - samedi 14 déc., Taher Alkhateeb a écrit : > Hello Gil, > > Great research on the subject, thank you for sharing. > > I could be wrong here, but at a first glance it seems you want to > essentially create a tag "<update-area ..." which essentially renders > another screen dynamically upon clicking / activating the URL. If my > understanding is correct, then most likely they way you want to > implement this is probably some web request to the backend which > renders back a partial screen that you insert into the DOM right? > > If what I describe above is close to your idea, then I think the > implementation might be relying on the server to do the work of > painting instead of relying on the browser to do the heavy lifting. > This also only works with one widget, which is the URL widget as > opposed to having a general purpose dynamic behavior in the system > (assuming this is desired). > > However, having a general purpose dynamic behavior means we need a > method to bind variables to values at the front end without consulting > the back-end. This reduces the load on the server and provides a > faster / richer experience to the user. But it would be too painful to > rely on plain javascript or jQuery to achieve such a result which is > the reason why frameworks like React, Vue, and others emerged as > modern SPA frameworks. Adopting an SPA framework would provide dynamic > behavior (everywhere) instead of certain widgets, and it can be > expanded to even include page navigation and whatnot. Of course this > is more work than what you're suggesting here. but if we continue with > such small improvements, you might end up having lots of javascript > (maybe that's already the case) which might increase the difficulty of > adopting an SPA framework in the future. > > So it comes down to this question (which I don't necessarily have an answer to): > > Do you want an SPA framework now or in the future, or do you want to > continue with status quo into the future? If you want an SPA > framework, then we should minimize the usage of custom javascript > everywhere and adopt a framework that completely replaces all the > javascript that currently exists for all the widgets. If not, then we > can proceed with your proposition and any others in the future knowing > that an overhaul is not needed. > > Cheers, > > Taher Alkhateeb > > On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne > <[hidden email]> wrote: > > > > Chapter One: How to manage the updating area > > > > Hello, > > > > After different discussions already listed by Taher [1-9], Leila, > > Nicolas and me tried another approach. > > Instead of analyzing how to implement different functionalities offered > > by modern js framework, we did analyzed how end user use, in general, > > OFBiz and where we, as an integrator, waste more time to create a > > screen. > > > > To help on this huge task, we set some basic rules : > > * Work only on screens supported by the theme, defined mainly in xml > > * This concerns only screens used for back-office applications, > > oriented to manage data > > * A developer does not have to know all of js language (or other) > > but can concentrate on the process/view with the end user to > > manage a data > > > > > > After a first brainstorm, we have identified three major cases : > > 1. Navigation and data display > > 2. View event result (data modification, calculation service, ...) > > 3. Update an area to refresh data (after data modification) > > > > Case 1 and 2 are easy and currently managed by OFBiz (and missing stuff > > will be simple to add), we concentrate our attention on case 3. > > > > To update an area, we follow this pattern > > > > 1. We start from a context that display different information > > > > 2. That context display a submit form, use a link or another > > mechanism to call an OFBiz event > > > > 3. After receiving the event return, we refresh the desired area > > with parameters that can come from origin context or from event > > return. > > > > > > Currently with the screen widget, we can use within a form the element > > `<on-event-update-area event-type="submit" area-id="" area-target=""/>`. > > > > The problem with this use, is that your form needs to know the origin > > context, to identify what are the areas to update and what are the > > target to use for the refresh. > > > > So your form needs to know where it comes from, what information need to > > be updated in OFBiz and what will be updated after. > > > > This increases complexity for the developer in the way that current form > > implementation manages : > > * the data and target to communicate with the server > > * the behaviour (refreshment) to apply when receiving server response. > > > > Example : > > <form name="EditPartyRoleCustomScreen" type="single" target="createPartyRole"> > > <field name="partyId"><hidden/></field> > > <field name="roleTypeId">... > > <on-event-update-area event-type="submit" area-id="PartyRoles_area" > > area-target="PartyRolesCustom"> > > <parameter param-name="partyId" from-field="parameters.partyId"/> > > </on-event-update-area> > > </form> > > > > If you want to reuse the same form, you need to create another screen > > with a new form to redefine the on-event-update-area (for instance > > create a PartyRole). > > > > We change the thinking, because since it is the starting context that > > better knows itself, it's the starting context that will realize the > > updating operation. The starting context is the screen/menu that call > > this form. > > > > In general a form is contained in a screen (classic) that is called > > through a link. So we move the idea on this link : > > > > <link target="CreatePartyRole" link-type="layered-modal"> > > <parameter param-name="partyId" from-field="customerParty.partyId"/> > > <update-area area-target="ResumeInfoCustomer" area-id="xxx"> > > <parameter param-name="partyId" from-field="customerParty.partyId"/> > > </update-area> > > </link> > > > > And the form : > > > > <form name="EditPartyRole" type="single" target="createPartyRole"> > > <field name="partyId"><hidden/></field> > > <field name="roleTypeId">... > > </form> > > > > With this logic you can define a new usage of createPartyRole > > without redefining a form just : > > > > <link target="CreatePartyRole" link-type="layered-modal"> > > <parameter param-name="partyId" from-field="partyRelationship.partyIdTo"/> > > <update-area area-target="MyRelationAndDetail" area-id="xxx"> > > <parameter param-name="partyId" from-field="partyRelationship.partyIdTo"/> > > <parameter param-name="partyRelationTypeId" value="IRL_LIKE"/> > > </update-area> > > </link> > > > > After some use we identified as pro and con feedback : > > * updating form is reusable and contains only code related to the > > form action > > * link being in origin context, the developer knows where he is and > > where he wants to go > > * Menu oriented management offers a quick vision on how the screen will works > > > > * update-area seems to be a too technical name > > * we always have to manage area to update manually > > * too many areas to update become a headache and not only for the developer > > > > We did not explain how we have done it, to try to focus the discussion > > on the principles. > > > > It would be a pleasure to have some criticism of this approach, and we > > would try, in a second chapter to introduce other concepts that appeared > > after the screens were made more dynamic and others to lowers the > > identified cons. > > > > Thanks, > > > > The Néréide Team > > > > [1] https://s.apache.org/rf94 > > [2] https://s.apache.org/g5zr > > [3] https://s.apache.org/XpBO > > [4] https://s.apache.org/YIL1 > > [5] https://s.apache.org/836D > > [6] https://s.apache.org/DhyB > > [7] https://s.apache.org/Lv9E > > [8] https://s.apache.org/zKIo > > [9] https://s.apache.org/D6jx > > |
In reply to this post by Gavin Mabie-2
Hello Gavin,
Thanks for four feedback, that's very interesting ! Could you elaborate about the OFBiz forms usage you did in your angular implementation ? You just used view-map with simple screen/form ? Cheers ! Gil Le 12:26 - mardi 17 déc., Gavin Mabie a écrit : > Hi Taher > > I've been using Angular for custom apps over the past year. This is my > approach: > > 1. Ofbiz deployed as an AppServer: > 1.1 Ofbiz controller resolves API request calls; > 1.2 Ofbiz Service Engine executes Services; > 1.3 Entity Engine for persistence; > 1.4 Returns JSON object - including Ofbiz context;; > 1.5 Ofbiz Forms used for additional business logic, fields etc; > 1.6 Ofbiz Screens not used at all. > > 2. Angular (On Apache HTTPD or Ionic/Cordova/JQueryMobile or even > JAVAFX(haven't tried this, but it's possible)): > 2.1 Typescripting types for Ofbiz entities used; > 2.2 Angular services for API calls corresponding to controller > request-mappings; > 2.3 Dynamic Angular Forms - based on Ofbiz Form defs; > 2.4 Other static content; > > 3. Authentication > 3.1 With JWT; > 3.2 Sessionless & no cookies; > 3.3 Ofbiz LoginWorker & Permission Engine for authorization; > > The big takeaway here is that Ofbiz Screens aren't used at all. Ofbiz > Forms are used to set fields, execute services and deal with issues like > locale etc. > > Cheers > > gavin > > > > > On Sat, Dec 14, 2019 at 6:52 PM Taher Alkhateeb <[hidden email]> > wrote: > > > Hello Gil, > > > > Great research on the subject, thank you for sharing. > > > > I could be wrong here, but at a first glance it seems you want to > > essentially create a tag "<update-area ..." which essentially renders > > another screen dynamically upon clicking / activating the URL. If my > > understanding is correct, then most likely they way you want to > > implement this is probably some web request to the backend which > > renders back a partial screen that you insert into the DOM right? > > > > If what I describe above is close to your idea, then I think the > > implementation might be relying on the server to do the work of > > painting instead of relying on the browser to do the heavy lifting. > > This also only works with one widget, which is the URL widget as > > opposed to having a general purpose dynamic behavior in the system > > (assuming this is desired). > > > > However, having a general purpose dynamic behavior means we need a > > method to bind variables to values at the front end without consulting > > the back-end. This reduces the load on the server and provides a > > faster / richer experience to the user. But it would be too painful to > > rely on plain javascript or jQuery to achieve such a result which is > > the reason why frameworks like React, Vue, and others emerged as > > modern SPA frameworks. Adopting an SPA framework would provide dynamic > > behavior (everywhere) instead of certain widgets, and it can be > > expanded to even include page navigation and whatnot. Of course this > > is more work than what you're suggesting here. but if we continue with > > such small improvements, you might end up having lots of javascript > > (maybe that's already the case) which might increase the difficulty of > > adopting an SPA framework in the future. > > > > So it comes down to this question (which I don't necessarily have an > > answer to): > > > > Do you want an SPA framework now or in the future, or do you want to > > continue with status quo into the future? If you want an SPA > > framework, then we should minimize the usage of custom javascript > > everywhere and adopt a framework that completely replaces all the > > javascript that currently exists for all the widgets. If not, then we > > can proceed with your proposition and any others in the future knowing > > that an overhaul is not needed. > > > > Cheers, > > > > Taher Alkhateeb > > > > On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne > > <[hidden email]> wrote: > > > > > > Chapter One: How to manage the updating area > > > > > > Hello, > > > > > > After different discussions already listed by Taher [1-9], Leila, > > > Nicolas and me tried another approach. > > > Instead of analyzing how to implement different functionalities offered > > > by modern js framework, we did analyzed how end user use, in general, > > > OFBiz and where we, as an integrator, waste more time to create a > > > screen. > > > > > > To help on this huge task, we set some basic rules : > > > * Work only on screens supported by the theme, defined mainly in xml > > > * This concerns only screens used for back-office applications, > > > oriented to manage data > > > * A developer does not have to know all of js language (or other) > > > but can concentrate on the process/view with the end user to > > > manage a data > > > > > > > > > After a first brainstorm, we have identified three major cases : > > > 1. Navigation and data display > > > 2. View event result (data modification, calculation service, ...) > > > 3. Update an area to refresh data (after data modification) > > > > > > Case 1 and 2 are easy and currently managed by OFBiz (and missing stuff > > > will be simple to add), we concentrate our attention on case 3. > > > > > > To update an area, we follow this pattern > > > > > > 1. We start from a context that display different information > > > > > > 2. That context display a submit form, use a link or another > > > mechanism to call an OFBiz event > > > > > > 3. After receiving the event return, we refresh the desired area > > > with parameters that can come from origin context or from event > > > return. > > > > > > > > > Currently with the screen widget, we can use within a form the element > > > `<on-event-update-area event-type="submit" area-id="" area-target=""/>`. > > > > > > The problem with this use, is that your form needs to know the origin > > > context, to identify what are the areas to update and what are the > > > target to use for the refresh. > > > > > > So your form needs to know where it comes from, what information need to > > > be updated in OFBiz and what will be updated after. > > > > > > This increases complexity for the developer in the way that current form > > > implementation manages : > > > * the data and target to communicate with the server > > > * the behaviour (refreshment) to apply when receiving server response. > > > > > > Example : > > > <form name="EditPartyRoleCustomScreen" type="single" > > target="createPartyRole"> > > > <field name="partyId"><hidden/></field> > > > <field name="roleTypeId">... > > > <on-event-update-area event-type="submit" > > area-id="PartyRoles_area" > > > area-target="PartyRolesCustom"> > > > <parameter param-name="partyId" > > from-field="parameters.partyId"/> > > > </on-event-update-area> > > > </form> > > > > > > If you want to reuse the same form, you need to create another screen > > > with a new form to redefine the on-event-update-area (for instance > > > create a PartyRole). > > > > > > We change the thinking, because since it is the starting context that > > > better knows itself, it's the starting context that will realize the > > > updating operation. The starting context is the screen/menu that call > > > this form. > > > > > > In general a form is contained in a screen (classic) that is called > > > through a link. So we move the idea on this link : > > > > > > <link target="CreatePartyRole" link-type="layered-modal"> > > > <parameter param-name="partyId" > > from-field="customerParty.partyId"/> > > > <update-area area-target="ResumeInfoCustomer" > > area-id="xxx"> > > > <parameter param-name="partyId" > > from-field="customerParty.partyId"/> > > > </update-area> > > > </link> > > > > > > And the form : > > > > > > <form name="EditPartyRole" type="single" > > target="createPartyRole"> > > > <field name="partyId"><hidden/></field> > > > <field name="roleTypeId">... > > > </form> > > > > > > With this logic you can define a new usage of createPartyRole > > > without redefining a form just : > > > > > > <link target="CreatePartyRole" link-type="layered-modal"> > > > <parameter param-name="partyId" > > from-field="partyRelationship.partyIdTo"/> > > > <update-area area-target="MyRelationAndDetail" > > area-id="xxx"> > > > <parameter param-name="partyId" > > from-field="partyRelationship.partyIdTo"/> > > > <parameter param-name="partyRelationTypeId" > > value="IRL_LIKE"/> > > > </update-area> > > > </link> > > > > > > After some use we identified as pro and con feedback : > > > * updating form is reusable and contains only code related to the > > > form action > > > * link being in origin context, the developer knows where he is and > > > where he wants to go > > > * Menu oriented management offers a quick vision on how the screen > > will works > > > > > > * update-area seems to be a too technical name > > > * we always have to manage area to update manually > > > * too many areas to update become a headache and not only for the > > developer > > > > > > We did not explain how we have done it, to try to focus the discussion > > > on the principles. > > > > > > It would be a pleasure to have some criticism of this approach, and we > > > would try, in a second chapter to introduce other concepts that appeared > > > after the screens were made more dynamic and others to lowers the > > > identified cons. > > > > > > Thanks, > > > > > > The Néréide Team > > > > > > [1] https://s.apache.org/rf94 > > > [2] https://s.apache.org/g5zr > > > [3] https://s.apache.org/XpBO > > > [4] https://s.apache.org/YIL1 > > > [5] https://s.apache.org/836D > > > [6] https://s.apache.org/DhyB > > > [7] https://s.apache.org/Lv9E > > > [8] https://s.apache.org/zKIo > > > [9] https://s.apache.org/D6jx > > > > > |
Hi Gil
I used a type=groovy service to resolve the form location eg. /* *@paramater formLocaction (where the form resides in the system) *@parameter formName (passed as request parameter) * returns an Ofbiz form entity with all the normal functionalties associated with ModelForm * this is returned to the http request as a JSON objecct */ ModelForm form = FormFactory.getFormFromLocation(formLocation, formName, entityModelReader, dispatchContext); Angular handles the response through a formField service which reads each Ofbiz formfields (JSON object) and creates a Angular reactive form from there. The Angualr formFields Service mirrors the Ofbiz field types etc. Regards Gavin On Tue, Dec 17, 2019 at 4:21 PM Gil Portenseigne < [hidden email]> wrote: > Hello Gavin, > > Thanks for four feedback, that's very interesting ! > > Could you elaborate about the OFBiz forms usage you did in your angular > implementation ? > You just used view-map with simple screen/form ? > > Cheers ! > > Gil > > Le 12:26 - mardi 17 déc., Gavin Mabie a écrit : > > Hi Taher > > > > I've been using Angular for custom apps over the past year. This is my > > approach: > > > > 1. Ofbiz deployed as an AppServer: > > 1.1 Ofbiz controller resolves API request calls; > > 1.2 Ofbiz Service Engine executes Services; > > 1.3 Entity Engine for persistence; > > 1.4 Returns JSON object - including Ofbiz context;; > > 1.5 Ofbiz Forms used for additional business logic, fields etc; > > 1.6 Ofbiz Screens not used at all. > > > > 2. Angular (On Apache HTTPD or Ionic/Cordova/JQueryMobile or even > > JAVAFX(haven't tried this, but it's possible)): > > 2.1 Typescripting types for Ofbiz entities used; > > 2.2 Angular services for API calls corresponding to controller > > request-mappings; > > 2.3 Dynamic Angular Forms - based on Ofbiz Form defs; > > 2.4 Other static content; > > > > 3. Authentication > > 3.1 With JWT; > > 3.2 Sessionless & no cookies; > > 3.3 Ofbiz LoginWorker & Permission Engine for authorization; > > > > The big takeaway here is that Ofbiz Screens aren't used at all. Ofbiz > > Forms are used to set fields, execute services and deal with issues like > > locale etc. > > > > Cheers > > > > gavin > > > > > > > > > > On Sat, Dec 14, 2019 at 6:52 PM Taher Alkhateeb < > [hidden email]> > > wrote: > > > > > Hello Gil, > > > > > > Great research on the subject, thank you for sharing. > > > > > > I could be wrong here, but at a first glance it seems you want to > > > essentially create a tag "<update-area ..." which essentially renders > > > another screen dynamically upon clicking / activating the URL. If my > > > understanding is correct, then most likely they way you want to > > > implement this is probably some web request to the backend which > > > renders back a partial screen that you insert into the DOM right? > > > > > > If what I describe above is close to your idea, then I think the > > > implementation might be relying on the server to do the work of > > > painting instead of relying on the browser to do the heavy lifting. > > > This also only works with one widget, which is the URL widget as > > > opposed to having a general purpose dynamic behavior in the system > > > (assuming this is desired). > > > > > > However, having a general purpose dynamic behavior means we need a > > > method to bind variables to values at the front end without consulting > > > the back-end. This reduces the load on the server and provides a > > > faster / richer experience to the user. But it would be too painful to > > > rely on plain javascript or jQuery to achieve such a result which is > > > the reason why frameworks like React, Vue, and others emerged as > > > modern SPA frameworks. Adopting an SPA framework would provide dynamic > > > behavior (everywhere) instead of certain widgets, and it can be > > > expanded to even include page navigation and whatnot. Of course this > > > is more work than what you're suggesting here. but if we continue with > > > such small improvements, you might end up having lots of javascript > > > (maybe that's already the case) which might increase the difficulty of > > > adopting an SPA framework in the future. > > > > > > So it comes down to this question (which I don't necessarily have an > > > answer to): > > > > > > Do you want an SPA framework now or in the future, or do you want to > > > continue with status quo into the future? If you want an SPA > > > framework, then we should minimize the usage of custom javascript > > > everywhere and adopt a framework that completely replaces all the > > > javascript that currently exists for all the widgets. If not, then we > > > can proceed with your proposition and any others in the future knowing > > > that an overhaul is not needed. > > > > > > Cheers, > > > > > > Taher Alkhateeb > > > > > > On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne > > > <[hidden email]> wrote: > > > > > > > > Chapter One: How to manage the updating area > > > > > > > > Hello, > > > > > > > > After different discussions already listed by Taher [1-9], Leila, > > > > Nicolas and me tried another approach. > > > > Instead of analyzing how to implement different functionalities > offered > > > > by modern js framework, we did analyzed how end user use, in general, > > > > OFBiz and where we, as an integrator, waste more time to create a > > > > screen. > > > > > > > > To help on this huge task, we set some basic rules : > > > > * Work only on screens supported by the theme, defined mainly in > xml > > > > * This concerns only screens used for back-office applications, > > > > oriented to manage data > > > > * A developer does not have to know all of js language (or other) > > > > but can concentrate on the process/view with the end user to > > > > manage a data > > > > > > > > > > > > After a first brainstorm, we have identified three major cases : > > > > 1. Navigation and data display > > > > 2. View event result (data modification, calculation service, > ...) > > > > 3. Update an area to refresh data (after data modification) > > > > > > > > Case 1 and 2 are easy and currently managed by OFBiz (and missing > stuff > > > > will be simple to add), we concentrate our attention on case 3. > > > > > > > > To update an area, we follow this pattern > > > > > > > > 1. We start from a context that display different information > > > > > > > > 2. That context display a submit form, use a link or another > > > > mechanism to call an OFBiz event > > > > > > > > 3. After receiving the event return, we refresh the desired area > > > > with parameters that can come from origin context or from event > > > > return. > > > > > > > > > > > > Currently with the screen widget, we can use within a form the > element > > > > `<on-event-update-area event-type="submit" area-id="" > area-target=""/>`. > > > > > > > > The problem with this use, is that your form needs to know the origin > > > > context, to identify what are the areas to update and what are the > > > > target to use for the refresh. > > > > > > > > So your form needs to know where it comes from, what information > need to > > > > be updated in OFBiz and what will be updated after. > > > > > > > > This increases complexity for the developer in the way that current > form > > > > implementation manages : > > > > * the data and target to communicate with the server > > > > * the behaviour (refreshment) to apply when receiving server > response. > > > > > > > > Example : > > > > <form name="EditPartyRoleCustomScreen" type="single" > > > target="createPartyRole"> > > > > <field name="partyId"><hidden/></field> > > > > <field name="roleTypeId">... > > > > <on-event-update-area event-type="submit" > > > area-id="PartyRoles_area" > > > > area-target="PartyRolesCustom"> > > > > <parameter param-name="partyId" > > > from-field="parameters.partyId"/> > > > > </on-event-update-area> > > > > </form> > > > > > > > > If you want to reuse the same form, you need to create another screen > > > > with a new form to redefine the on-event-update-area (for instance > > > > create a PartyRole). > > > > > > > > We change the thinking, because since it is the starting context that > > > > better knows itself, it's the starting context that will realize the > > > > updating operation. The starting context is the screen/menu that call > > > > this form. > > > > > > > > In general a form is contained in a screen (classic) that is called > > > > through a link. So we move the idea on this link : > > > > > > > > <link target="CreatePartyRole" link-type="layered-modal"> > > > > <parameter param-name="partyId" > > > from-field="customerParty.partyId"/> > > > > <update-area area-target="ResumeInfoCustomer" > > > area-id="xxx"> > > > > <parameter param-name="partyId" > > > from-field="customerParty.partyId"/> > > > > </update-area> > > > > </link> > > > > > > > > And the form : > > > > > > > > <form name="EditPartyRole" type="single" > > > target="createPartyRole"> > > > > <field name="partyId"><hidden/></field> > > > > <field name="roleTypeId">... > > > > </form> > > > > > > > > With this logic you can define a new usage of createPartyRole > > > > without redefining a form just : > > > > > > > > <link target="CreatePartyRole" link-type="layered-modal"> > > > > <parameter param-name="partyId" > > > from-field="partyRelationship.partyIdTo"/> > > > > <update-area area-target="MyRelationAndDetail" > > > area-id="xxx"> > > > > <parameter param-name="partyId" > > > from-field="partyRelationship.partyIdTo"/> > > > > <parameter param-name="partyRelationTypeId" > > > value="IRL_LIKE"/> > > > > </update-area> > > > > </link> > > > > > > > > After some use we identified as pro and con feedback : > > > > * updating form is reusable and contains only code related to the > > > > form action > > > > * link being in origin context, the developer knows where he is > and > > > > where he wants to go > > > > * Menu oriented management offers a quick vision on how the > screen > > > will works > > > > > > > > * update-area seems to be a too technical name > > > > * we always have to manage area to update manually > > > > * too many areas to update become a headache and not only for the > > > developer > > > > > > > > We did not explain how we have done it, to try to focus the > discussion > > > > on the principles. > > > > > > > > It would be a pleasure to have some criticism of this approach, and > we > > > > would try, in a second chapter to introduce other concepts that > appeared > > > > after the screens were made more dynamic and others to lowers the > > > > identified cons. > > > > > > > > Thanks, > > > > > > > > The Néréide Team > > > > > > > > [1] https://s.apache.org/rf94 > > > > [2] https://s.apache.org/g5zr > > > > [3] https://s.apache.org/XpBO > > > > [4] https://s.apache.org/YIL1 > > > > [5] https://s.apache.org/836D > > > > [6] https://s.apache.org/DhyB > > > > [7] https://s.apache.org/Lv9E > > > > [8] https://s.apache.org/zKIo > > > > [9] https://s.apache.org/D6jx > > > > > > > > |
Here's a more complete snippet to get a form - in Groovy.
if(formLocation) { String delegatorName = delegator.getDelegatorName(); if (delegatorName.contains("default#")) { delegatorName = "default"; } DispatchContext dispatchContext = dispatcher.getDispatchContext(); ModelReader entityModelReader = ModelReader.getModelReader(delegatorName); ModelForm form = FormFactory.getFormFromLocation(formLocation, formName, entityModelReader, dispatchContext); if(form) { form.runFormActions(context); target = form.getTarget(context,form.getTargetType()); targetWindow = form.getTargetWindow(context); defaultMapName = form.getDefaultMapName(); fieldList = form.getFieldList(); fieldList.each{field -> } for(ModelFormField modelFormField in fieldList) { ModelFormField.FieldInfo currentFieldInfo = modelFormField.getFieldInfo(); if (currentFieldInfo != null) { ModelFormField fieldInfoFormField = currentFieldInfo.getModelFormField(); if (fieldInfoFormField != null) { fieldInfoFormField.setModelForm(form); } } else { throw new IllegalArgumentException("Error rendering form, a field has no FieldInfo, ie no sub-element for the type of field for field named: " + modelFormField.getName()); } } List<ModelFormField> tempFieldList = FastList.newInstance(); tempFieldList.addAll(fieldList); //Debug.logInfo("fieldList size: "+form.useWhe+" tempFieldList size: "+tempFieldList.size(),""); for (int j = 0; j < tempFieldList.size(); j++) { ModelFormField modelFormField = tempFieldList.get(j); if (form.useWhenFields.contains(modelFormField.getName())) { boolean shouldUse1 = modelFormField.shouldUse(context); for (int i = j+1; i < tempFieldList.size(); i++) { ModelFormField curField = tempFieldList.get(i); if (curField.getName() != null && curField.getName().equals(modelFormField.getName())) { boolean shouldUse2 = curField.shouldUse(context); if (shouldUse1 == shouldUse2) { tempFieldList.remove(i--); } } else { continue; } } } } Set<String> alreadyRendered = new TreeSet<String>(); List<ModelFormField> hiddenIgnoredFieldList = form.getHiddenIgnoredFields(context, alreadyRendered, tempFieldList, -1); //renderHiddenIgnoreFields for(ModelFormField modelFormField in hiddenIgnoredFieldList) { fieldMap = [:]; fieldMap.title = modelFormField.getTitle(context); fieldMap.name = modelFormField.getParameterName(context); fieldMap.action = modelFormField.getAction(context); fieldMap.event = modelFormField.getEvent(); fieldMap.id = modelFormField.getCurrentContainerId(context); fieldMap.value = modelFormField.getEntry(context); fieldMap.required = modelFormField.getRequiredField(); ModelFormField.FieldInfo fieldInfo = modelFormField.getFieldInfo(); switch(fieldInfo.getFieldType()) { case ModelFormField.FieldInfo.HIDDEN : fieldMap.type = "hidden"; break; case ModelFormField.FieldInfo.IGNORED : fieldMap.type = "ignored"; break; case ModelFormField.FieldInfo.DISPLAY : fieldMap.type = "display"; break; case ModelFormField.FieldInfo.DISPLAY_ENTITY : fieldMap.type = "displayEntity"; break; case ModelFormField.FieldInfo.HYPERLINK : fieldMap.type = "hyperlink"; break; } if(fieldInfo.getFieldType() != ModelFormField.FieldInfo.IGNORED) { fields.add(fieldMap); } } Iterator<ModelFormField> fieldIter = tempFieldList.iterator(); ModelFormField lastFormField = null; ModelFormField currentFormField = null; ModelFormField nextFormField = null; if (fieldIter.hasNext()) { currentFormField = fieldIter.next(); //ModelFormField.FieldInfo fieldInfo = currentFormField.getFieldInfo(); //Debug.logInfo("currentFormField : "+currentFormField.getName(),""); }else { lastFormField = currentFormField; currentFormField = null; } if (fieldIter.hasNext()) { nextFormField = fieldIter.next(); } while(fieldIter.hasNext()) { currentFormField = fieldIter.next(); //Debug.logInfo("currentFormField : "+currentFormField.getName(),""); ModelFormField.FieldInfo fieldInfo = currentFormField.getFieldInfo(); if (fieldInfo.getFieldType() == ModelFormField.FieldInfo.HIDDEN || fieldInfo.getFieldType() == ModelFormField.FieldInfo.IGNORED) { //Debug.logInfo("continuing : HIDDEN/IGNORED",""); continue; } if (alreadyRendered.contains(currentFormField.getName())) { //Debug.logInfo("continuing : alreadyRendered",""); continue; } if (!currentFormField.shouldUse(context)) { if (UtilValidate.isNotEmpty(lastFormField)) { currentFormField = lastFormField; } continue; } alreadyRendered.add(currentFormField.getName()); fieldMap = getFieldMap(fieldInfo,context); fieldMap.each{key, val -> } fields.add(fieldMap); } } } Gavin On Tue, Dec 17, 2019 at 5:05 PM Gavin Mabie <[hidden email]> wrote: > Hi Gil > > I used a type=groovy service to resolve the form location eg. > /* > *@paramater formLocaction (where the form resides in the system) > *@parameter formName (passed as request parameter) > * returns an Ofbiz form entity with all the normal functionalties > associated with ModelForm > * this is returned to the http request as a JSON objecct > */ > ModelForm form = FormFactory.getFormFromLocation(formLocation, formName, > entityModelReader, dispatchContext); > > Angular handles the response through a formField service which reads each > Ofbiz formfields (JSON object) and creates a Angular reactive form from > there. The Angualr formFields Service mirrors the Ofbiz field types etc. > > Regards > > Gavin > > > > > > > > On Tue, Dec 17, 2019 at 4:21 PM Gil Portenseigne < > [hidden email]> wrote: > >> Hello Gavin, >> >> Thanks for four feedback, that's very interesting ! >> >> Could you elaborate about the OFBiz forms usage you did in your angular >> implementation ? >> You just used view-map with simple screen/form ? >> >> Cheers ! >> >> Gil >> >> Le 12:26 - mardi 17 déc., Gavin Mabie a écrit : >> > Hi Taher >> > >> > I've been using Angular for custom apps over the past year. This is my >> > approach: >> > >> > 1. Ofbiz deployed as an AppServer: >> > 1.1 Ofbiz controller resolves API request calls; >> > 1.2 Ofbiz Service Engine executes Services; >> > 1.3 Entity Engine for persistence; >> > 1.4 Returns JSON object - including Ofbiz context;; >> > 1.5 Ofbiz Forms used for additional business logic, fields etc; >> > 1.6 Ofbiz Screens not used at all. >> > >> > 2. Angular (On Apache HTTPD or Ionic/Cordova/JQueryMobile or even >> > JAVAFX(haven't tried this, but it's possible)): >> > 2.1 Typescripting types for Ofbiz entities used; >> > 2.2 Angular services for API calls corresponding to controller >> > request-mappings; >> > 2.3 Dynamic Angular Forms - based on Ofbiz Form defs; >> > 2.4 Other static content; >> > >> > 3. Authentication >> > 3.1 With JWT; >> > 3.2 Sessionless & no cookies; >> > 3.3 Ofbiz LoginWorker & Permission Engine for authorization; >> > >> > The big takeaway here is that Ofbiz Screens aren't used at all. Ofbiz >> > Forms are used to set fields, execute services and deal with issues like >> > locale etc. >> > >> > Cheers >> > >> > gavin >> > >> > >> > >> > >> > On Sat, Dec 14, 2019 at 6:52 PM Taher Alkhateeb < >> [hidden email]> >> > wrote: >> > >> > > Hello Gil, >> > > >> > > Great research on the subject, thank you for sharing. >> > > >> > > I could be wrong here, but at a first glance it seems you want to >> > > essentially create a tag "<update-area ..." which essentially renders >> > > another screen dynamically upon clicking / activating the URL. If my >> > > understanding is correct, then most likely they way you want to >> > > implement this is probably some web request to the backend which >> > > renders back a partial screen that you insert into the DOM right? >> > > >> > > If what I describe above is close to your idea, then I think the >> > > implementation might be relying on the server to do the work of >> > > painting instead of relying on the browser to do the heavy lifting. >> > > This also only works with one widget, which is the URL widget as >> > > opposed to having a general purpose dynamic behavior in the system >> > > (assuming this is desired). >> > > >> > > However, having a general purpose dynamic behavior means we need a >> > > method to bind variables to values at the front end without consulting >> > > the back-end. This reduces the load on the server and provides a >> > > faster / richer experience to the user. But it would be too painful to >> > > rely on plain javascript or jQuery to achieve such a result which is >> > > the reason why frameworks like React, Vue, and others emerged as >> > > modern SPA frameworks. Adopting an SPA framework would provide dynamic >> > > behavior (everywhere) instead of certain widgets, and it can be >> > > expanded to even include page navigation and whatnot. Of course this >> > > is more work than what you're suggesting here. but if we continue with >> > > such small improvements, you might end up having lots of javascript >> > > (maybe that's already the case) which might increase the difficulty of >> > > adopting an SPA framework in the future. >> > > >> > > So it comes down to this question (which I don't necessarily have an >> > > answer to): >> > > >> > > Do you want an SPA framework now or in the future, or do you want to >> > > continue with status quo into the future? If you want an SPA >> > > framework, then we should minimize the usage of custom javascript >> > > everywhere and adopt a framework that completely replaces all the >> > > javascript that currently exists for all the widgets. If not, then we >> > > can proceed with your proposition and any others in the future knowing >> > > that an overhaul is not needed. >> > > >> > > Cheers, >> > > >> > > Taher Alkhateeb >> > > >> > > On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne >> > > <[hidden email]> wrote: >> > > > >> > > > Chapter One: How to manage the updating area >> > > > >> > > > Hello, >> > > > >> > > > After different discussions already listed by Taher [1-9], Leila, >> > > > Nicolas and me tried another approach. >> > > > Instead of analyzing how to implement different functionalities >> offered >> > > > by modern js framework, we did analyzed how end user use, in >> general, >> > > > OFBiz and where we, as an integrator, waste more time to create a >> > > > screen. >> > > > >> > > > To help on this huge task, we set some basic rules : >> > > > * Work only on screens supported by the theme, defined mainly >> in xml >> > > > * This concerns only screens used for back-office applications, >> > > > oriented to manage data >> > > > * A developer does not have to know all of js language (or >> other) >> > > > but can concentrate on the process/view with the end user to >> > > > manage a data >> > > > >> > > > >> > > > After a first brainstorm, we have identified three major cases : >> > > > 1. Navigation and data display >> > > > 2. View event result (data modification, calculation service, >> ...) >> > > > 3. Update an area to refresh data (after data modification) >> > > > >> > > > Case 1 and 2 are easy and currently managed by OFBiz (and missing >> stuff >> > > > will be simple to add), we concentrate our attention on case 3. >> > > > >> > > > To update an area, we follow this pattern >> > > > >> > > > 1. We start from a context that display different information >> > > > >> > > > 2. That context display a submit form, use a link or another >> > > > mechanism to call an OFBiz event >> > > > >> > > > 3. After receiving the event return, we refresh the desired area >> > > > with parameters that can come from origin context or from event >> > > > return. >> > > > >> > > > >> > > > Currently with the screen widget, we can use within a form the >> element >> > > > `<on-event-update-area event-type="submit" area-id="" >> area-target=""/>`. >> > > > >> > > > The problem with this use, is that your form needs to know the >> origin >> > > > context, to identify what are the areas to update and what are the >> > > > target to use for the refresh. >> > > > >> > > > So your form needs to know where it comes from, what information >> need to >> > > > be updated in OFBiz and what will be updated after. >> > > > >> > > > This increases complexity for the developer in the way that current >> form >> > > > implementation manages : >> > > > * the data and target to communicate with the server >> > > > * the behaviour (refreshment) to apply when receiving server >> response. >> > > > >> > > > Example : >> > > > <form name="EditPartyRoleCustomScreen" type="single" >> > > target="createPartyRole"> >> > > > <field name="partyId"><hidden/></field> >> > > > <field name="roleTypeId">... >> > > > <on-event-update-area event-type="submit" >> > > area-id="PartyRoles_area" >> > > > area-target="PartyRolesCustom"> >> > > > <parameter param-name="partyId" >> > > from-field="parameters.partyId"/> >> > > > </on-event-update-area> >> > > > </form> >> > > > >> > > > If you want to reuse the same form, you need to create another >> screen >> > > > with a new form to redefine the on-event-update-area (for instance >> > > > create a PartyRole). >> > > > >> > > > We change the thinking, because since it is the starting context >> that >> > > > better knows itself, it's the starting context that will realize the >> > > > updating operation. The starting context is the screen/menu that >> call >> > > > this form. >> > > > >> > > > In general a form is contained in a screen (classic) that is called >> > > > through a link. So we move the idea on this link : >> > > > >> > > > <link target="CreatePartyRole" >> link-type="layered-modal"> >> > > > <parameter param-name="partyId" >> > > from-field="customerParty.partyId"/> >> > > > <update-area area-target="ResumeInfoCustomer" >> > > area-id="xxx"> >> > > > <parameter param-name="partyId" >> > > from-field="customerParty.partyId"/> >> > > > </update-area> >> > > > </link> >> > > > >> > > > And the form : >> > > > >> > > > <form name="EditPartyRole" type="single" >> > > target="createPartyRole"> >> > > > <field name="partyId"><hidden/></field> >> > > > <field name="roleTypeId">... >> > > > </form> >> > > > >> > > > With this logic you can define a new usage of >> createPartyRole >> > > > without redefining a form just : >> > > > >> > > > <link target="CreatePartyRole" >> link-type="layered-modal"> >> > > > <parameter param-name="partyId" >> > > from-field="partyRelationship.partyIdTo"/> >> > > > <update-area area-target="MyRelationAndDetail" >> > > area-id="xxx"> >> > > > <parameter param-name="partyId" >> > > from-field="partyRelationship.partyIdTo"/> >> > > > <parameter param-name="partyRelationTypeId" >> > > value="IRL_LIKE"/> >> > > > </update-area> >> > > > </link> >> > > > >> > > > After some use we identified as pro and con feedback : >> > > > * updating form is reusable and contains only code related to >> the >> > > > form action >> > > > * link being in origin context, the developer knows where he is >> and >> > > > where he wants to go >> > > > * Menu oriented management offers a quick vision on how the >> screen >> > > will works >> > > > >> > > > * update-area seems to be a too technical name >> > > > * we always have to manage area to update manually >> > > > * too many areas to update become a headache and not only for >> the >> > > developer >> > > > >> > > > We did not explain how we have done it, to try to focus the >> discussion >> > > > on the principles. >> > > > >> > > > It would be a pleasure to have some criticism of this approach, and >> we >> > > > would try, in a second chapter to introduce other concepts that >> appeared >> > > > after the screens were made more dynamic and others to lowers the >> > > > identified cons. >> > > > >> > > > Thanks, >> > > > >> > > > The Néréide Team >> > > > >> > > > [1] https://s.apache.org/rf94 >> > > > [2] https://s.apache.org/g5zr >> > > > [3] https://s.apache.org/XpBO >> > > > [4] https://s.apache.org/YIL1 >> > > > [5] https://s.apache.org/836D >> > > > [6] https://s.apache.org/DhyB >> > > > [7] https://s.apache.org/Lv9E >> > > > [8] https://s.apache.org/zKIo >> > > > [9] https://s.apache.org/D6jx >> > > > >> > > >> > |
Example of Angular-Ofbiz formField Service
import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { of as observableOf,Observable } from 'rxjs'; import { OfbizForm, OfbizFormFieldsBase, OfbizTexboxField, OfbizDisplayField, OfbizDateTimeField, OfbizDropdownField, OfbizHiddenField } from '../Types/ofbiz-forms'; import { tap, map } from 'rxjs/operators'; import { FormControl, Validators, FormGroup } from '@angular/forms'; @Injectable({ providedIn: 'root' }) export class OfbizFormService { baseUrl:string = "https://**********"; constructor(private http: HttpClient) { } getForm(options:any):Observable<any>{ console.log(options); return this.http.get<OfbizForm>(this.baseUrl,options) .pipe( tap(() => console.log('HTTP request executed')), map(resp => resp) ); } toFormGroup(formFields: OfbizFormFieldsBase<any>[]){ let group:any = {}; formFields.forEach(formField => { group[formField.name] = formField.required ? new FormControl(formField.value || '',Validators.required) : new FormControl(formField.value || ''); }); return new FormGroup(group); } getFormFields(rawFields:any[]):Observable<any>{ let fields:OfbizFormFieldsBase<any>[]=[]; rawFields.forEach((field,i) => { let currentValue = null; if(field.value){ currentValue = field.value; }else{ currentValue = field.currentValue; } switch(field.type){ case "hidden": console.log("This is a display"); let hiddenField = new OfbizHiddenField({ key:field.id, label:field.title, value:field.value, name:field.name, order:i, required:field.required, }); fields.push(hiddenField); break; case "display": console.log("This is a display"); let displayfield = new OfbizDisplayField({ key:field.id, label:field.title, value:field.value, name:field.name, order:i, required:field.required, }); fields.push(displayfield); break; case "text": console.log("This is a input"); let textBoxField = new OfbizTexboxField({ key:field.id, label:field.title, value:field.value, name:field.name, order:i, required:field.required, }); fields.push(textBoxField); break; case 'datetime': console.log("This is a input"); let datetimeField = new OfbizDateTimeField({ key:field.id, label:field.title, value:field.value, name:field.name, order:i, required:field.required, }); fields.push(datetimeField); break; case "dropdown": let dropDownField = new OfbizDropdownField({ key:field.id, label:field.title, value:field.value, name:field.name, order:i, required:field.required, options:this.convertOptions(field.allOptionValues), }); fields.push(dropDownField); break; } }); fields.sort((a, b) => a.order - b.order); return observableOf(fields); } convertOptions(allOptionValues:any[]){ let options = []; allOptionValues.forEach(allOptionValue => { let entry = {}; entry['value'] = allOptionValue.key; entry['key'] = allOptionValue.description; options.push(entry); }); return options; } submitForm(form:any,target:string):Observable<any>{ console.log(target); let url:string = "https://api-homeinit.edupen.co.za/homeinit/control/ "+target; const httpOptions = { headers:new HttpHeaders({ 'Content-Type':'application/json' }) } return this.http.post(url,form,httpOptions) .pipe( map(resp =>resp) ); } } Gavin On Tue, Dec 17, 2019 at 5:18 PM Gavin Mabie <[hidden email]> wrote: > Here's a more complete snippet to get a form - in Groovy. > > if(formLocation) { > String delegatorName = delegator.getDelegatorName(); > if (delegatorName.contains("default#")) { > delegatorName = "default"; > } > DispatchContext dispatchContext = dispatcher.getDispatchContext(); > ModelReader entityModelReader = ModelReader.getModelReader(delegatorName); > ModelForm form = FormFactory.getFormFromLocation(formLocation, formName, > entityModelReader, dispatchContext); > if(form) { > form.runFormActions(context); > target = form.getTarget(context,form.getTargetType()); > targetWindow = form.getTargetWindow(context); > defaultMapName = form.getDefaultMapName(); > > fieldList = form.getFieldList(); > fieldList.each{field -> > } > > for(ModelFormField modelFormField in fieldList) { > ModelFormField.FieldInfo currentFieldInfo = modelFormField.getFieldInfo(); > if (currentFieldInfo != null) { > ModelFormField fieldInfoFormField = currentFieldInfo.getModelFormField(); > if (fieldInfoFormField != null) { > fieldInfoFormField.setModelForm(form); > } > } else { > throw new IllegalArgumentException("Error rendering form, a field has > no FieldInfo, ie no sub-element for the type of field for field named: " + > modelFormField.getName()); > } > > } > > List<ModelFormField> tempFieldList = FastList.newInstance(); > tempFieldList.addAll(fieldList); > //Debug.logInfo("fieldList size: "+form.useWhe+" tempFieldList size: > "+tempFieldList.size(),""); > > for (int j = 0; j < tempFieldList.size(); j++) { > ModelFormField modelFormField = tempFieldList.get(j); > if (form.useWhenFields.contains(modelFormField.getName())) { > boolean shouldUse1 = modelFormField.shouldUse(context); > for (int i = j+1; i < tempFieldList.size(); i++) { > ModelFormField curField = tempFieldList.get(i); > if (curField.getName() != null && > curField.getName().equals(modelFormField.getName())) { > boolean shouldUse2 = curField.shouldUse(context); > if (shouldUse1 == shouldUse2) { > tempFieldList.remove(i--); > } > } else { > continue; > } > } > } > } > Set<String> alreadyRendered = new TreeSet<String>(); > > List<ModelFormField> hiddenIgnoredFieldList = > form.getHiddenIgnoredFields(context, alreadyRendered, tempFieldList, -1); > //renderHiddenIgnoreFields > for(ModelFormField modelFormField in hiddenIgnoredFieldList) { > fieldMap = [:]; > fieldMap.title = modelFormField.getTitle(context); > fieldMap.name = modelFormField.getParameterName(context); > fieldMap.action = modelFormField.getAction(context); > fieldMap.event = modelFormField.getEvent(); > fieldMap.id = modelFormField.getCurrentContainerId(context); > fieldMap.value = modelFormField.getEntry(context); > fieldMap.required = modelFormField.getRequiredField(); > ModelFormField.FieldInfo fieldInfo = modelFormField.getFieldInfo(); > switch(fieldInfo.getFieldType()) { > case ModelFormField.FieldInfo.HIDDEN : > fieldMap.type = "hidden"; > break; > case ModelFormField.FieldInfo.IGNORED : > fieldMap.type = "ignored"; > break; > case ModelFormField.FieldInfo.DISPLAY : > fieldMap.type = "display"; > break; > case ModelFormField.FieldInfo.DISPLAY_ENTITY : > fieldMap.type = "displayEntity"; > break; > case ModelFormField.FieldInfo.HYPERLINK : > fieldMap.type = "hyperlink"; > break; > } > if(fieldInfo.getFieldType() != ModelFormField.FieldInfo.IGNORED) { > fields.add(fieldMap); > } > } > > Iterator<ModelFormField> fieldIter = tempFieldList.iterator(); > ModelFormField lastFormField = null; > ModelFormField currentFormField = null; > ModelFormField nextFormField = null; > if (fieldIter.hasNext()) { > currentFormField = fieldIter.next(); > //ModelFormField.FieldInfo fieldInfo = currentFormField.getFieldInfo(); > //Debug.logInfo("currentFormField : "+currentFormField.getName(),""); > }else { > lastFormField = currentFormField; > currentFormField = null; > } > if (fieldIter.hasNext()) { > nextFormField = fieldIter.next(); > } > while(fieldIter.hasNext()) { > currentFormField = fieldIter.next(); > //Debug.logInfo("currentFormField : "+currentFormField.getName(),""); > ModelFormField.FieldInfo fieldInfo = currentFormField.getFieldInfo(); > if (fieldInfo.getFieldType() == ModelFormField.FieldInfo.HIDDEN || > fieldInfo.getFieldType() == ModelFormField.FieldInfo.IGNORED) { > //Debug.logInfo("continuing : HIDDEN/IGNORED",""); > continue; > } > if (alreadyRendered.contains(currentFormField.getName())) { > //Debug.logInfo("continuing : alreadyRendered",""); > continue; > } > if (!currentFormField.shouldUse(context)) { > if (UtilValidate.isNotEmpty(lastFormField)) { > currentFormField = lastFormField; > } > continue; > } > alreadyRendered.add(currentFormField.getName()); > fieldMap = getFieldMap(fieldInfo,context); > fieldMap.each{key, val -> > } > fields.add(fieldMap); > > } > > } > > } > > Gavin > > On Tue, Dec 17, 2019 at 5:05 PM Gavin Mabie <[hidden email]> wrote: > >> Hi Gil >> >> I used a type=groovy service to resolve the form location eg. >> /* >> *@paramater formLocaction (where the form resides in the system) >> *@parameter formName (passed as request parameter) >> * returns an Ofbiz form entity with all the normal functionalties >> associated with ModelForm >> * this is returned to the http request as a JSON objecct >> */ >> ModelForm form = FormFactory.getFormFromLocation(formLocation, formName, >> entityModelReader, dispatchContext); >> >> Angular handles the response through a formField service which reads each >> Ofbiz formfields (JSON object) and creates a Angular reactive form from >> there. The Angualr formFields Service mirrors the Ofbiz field types etc. >> >> Regards >> >> Gavin >> >> >> >> >> >> >> >> On Tue, Dec 17, 2019 at 4:21 PM Gil Portenseigne < >> [hidden email]> wrote: >> >>> Hello Gavin, >>> >>> Thanks for four feedback, that's very interesting ! >>> >>> Could you elaborate about the OFBiz forms usage you did in your angular >>> implementation ? >>> You just used view-map with simple screen/form ? >>> >>> Cheers ! >>> >>> Gil >>> >>> Le 12:26 - mardi 17 déc., Gavin Mabie a écrit : >>> > Hi Taher >>> > >>> > I've been using Angular for custom apps over the past year. This is my >>> > approach: >>> > >>> > 1. Ofbiz deployed as an AppServer: >>> > 1.1 Ofbiz controller resolves API request calls; >>> > 1.2 Ofbiz Service Engine executes Services; >>> > 1.3 Entity Engine for persistence; >>> > 1.4 Returns JSON object - including Ofbiz context;; >>> > 1.5 Ofbiz Forms used for additional business logic, fields etc; >>> > 1.6 Ofbiz Screens not used at all. >>> > >>> > 2. Angular (On Apache HTTPD or Ionic/Cordova/JQueryMobile or even >>> > JAVAFX(haven't tried this, but it's possible)): >>> > 2.1 Typescripting types for Ofbiz entities used; >>> > 2.2 Angular services for API calls corresponding to controller >>> > request-mappings; >>> > 2.3 Dynamic Angular Forms - based on Ofbiz Form defs; >>> > 2.4 Other static content; >>> > >>> > 3. Authentication >>> > 3.1 With JWT; >>> > 3.2 Sessionless & no cookies; >>> > 3.3 Ofbiz LoginWorker & Permission Engine for authorization; >>> > >>> > The big takeaway here is that Ofbiz Screens aren't used at all. Ofbiz >>> > Forms are used to set fields, execute services and deal with issues >>> like >>> > locale etc. >>> > >>> > Cheers >>> > >>> > gavin >>> > >>> > >>> > >>> > >>> > On Sat, Dec 14, 2019 at 6:52 PM Taher Alkhateeb < >>> [hidden email]> >>> > wrote: >>> > >>> > > Hello Gil, >>> > > >>> > > Great research on the subject, thank you for sharing. >>> > > >>> > > I could be wrong here, but at a first glance it seems you want to >>> > > essentially create a tag "<update-area ..." which essentially renders >>> > > another screen dynamically upon clicking / activating the URL. If my >>> > > understanding is correct, then most likely they way you want to >>> > > implement this is probably some web request to the backend which >>> > > renders back a partial screen that you insert into the DOM right? >>> > > >>> > > If what I describe above is close to your idea, then I think the >>> > > implementation might be relying on the server to do the work of >>> > > painting instead of relying on the browser to do the heavy lifting. >>> > > This also only works with one widget, which is the URL widget as >>> > > opposed to having a general purpose dynamic behavior in the system >>> > > (assuming this is desired). >>> > > >>> > > However, having a general purpose dynamic behavior means we need a >>> > > method to bind variables to values at the front end without >>> consulting >>> > > the back-end. This reduces the load on the server and provides a >>> > > faster / richer experience to the user. But it would be too painful >>> to >>> > > rely on plain javascript or jQuery to achieve such a result which is >>> > > the reason why frameworks like React, Vue, and others emerged as >>> > > modern SPA frameworks. Adopting an SPA framework would provide >>> dynamic >>> > > behavior (everywhere) instead of certain widgets, and it can be >>> > > expanded to even include page navigation and whatnot. Of course this >>> > > is more work than what you're suggesting here. but if we continue >>> with >>> > > such small improvements, you might end up having lots of javascript >>> > > (maybe that's already the case) which might increase the difficulty >>> of >>> > > adopting an SPA framework in the future. >>> > > >>> > > So it comes down to this question (which I don't necessarily have an >>> > > answer to): >>> > > >>> > > Do you want an SPA framework now or in the future, or do you want to >>> > > continue with status quo into the future? If you want an SPA >>> > > framework, then we should minimize the usage of custom javascript >>> > > everywhere and adopt a framework that completely replaces all the >>> > > javascript that currently exists for all the widgets. If not, then we >>> > > can proceed with your proposition and any others in the future >>> knowing >>> > > that an overhaul is not needed. >>> > > >>> > > Cheers, >>> > > >>> > > Taher Alkhateeb >>> > > >>> > > On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne >>> > > <[hidden email]> wrote: >>> > > > >>> > > > Chapter One: How to manage the updating area >>> > > > >>> > > > Hello, >>> > > > >>> > > > After different discussions already listed by Taher [1-9], Leila, >>> > > > Nicolas and me tried another approach. >>> > > > Instead of analyzing how to implement different functionalities >>> offered >>> > > > by modern js framework, we did analyzed how end user use, in >>> general, >>> > > > OFBiz and where we, as an integrator, waste more time to create a >>> > > > screen. >>> > > > >>> > > > To help on this huge task, we set some basic rules : >>> > > > * Work only on screens supported by the theme, defined mainly >>> in xml >>> > > > * This concerns only screens used for back-office applications, >>> > > > oriented to manage data >>> > > > * A developer does not have to know all of js language (or >>> other) >>> > > > but can concentrate on the process/view with the end user to >>> > > > manage a data >>> > > > >>> > > > >>> > > > After a first brainstorm, we have identified three major cases : >>> > > > 1. Navigation and data display >>> > > > 2. View event result (data modification, calculation service, >>> ...) >>> > > > 3. Update an area to refresh data (after data modification) >>> > > > >>> > > > Case 1 and 2 are easy and currently managed by OFBiz (and missing >>> stuff >>> > > > will be simple to add), we concentrate our attention on case 3. >>> > > > >>> > > > To update an area, we follow this pattern >>> > > > >>> > > > 1. We start from a context that display different information >>> > > > >>> > > > 2. That context display a submit form, use a link or another >>> > > > mechanism to call an OFBiz event >>> > > > >>> > > > 3. After receiving the event return, we refresh the desired >>> area >>> > > > with parameters that can come from origin context or from event >>> > > > return. >>> > > > >>> > > > >>> > > > Currently with the screen widget, we can use within a form the >>> element >>> > > > `<on-event-update-area event-type="submit" area-id="" >>> area-target=""/>`. >>> > > > >>> > > > The problem with this use, is that your form needs to know the >>> origin >>> > > > context, to identify what are the areas to update and what are the >>> > > > target to use for the refresh. >>> > > > >>> > > > So your form needs to know where it comes from, what information >>> need to >>> > > > be updated in OFBiz and what will be updated after. >>> > > > >>> > > > This increases complexity for the developer in the way that >>> current form >>> > > > implementation manages : >>> > > > * the data and target to communicate with the server >>> > > > * the behaviour (refreshment) to apply when receiving server >>> response. >>> > > > >>> > > > Example : >>> > > > <form name="EditPartyRoleCustomScreen" type="single" >>> > > target="createPartyRole"> >>> > > > <field name="partyId"><hidden/></field> >>> > > > <field name="roleTypeId">... >>> > > > <on-event-update-area event-type="submit" >>> > > area-id="PartyRoles_area" >>> > > > area-target="PartyRolesCustom"> >>> > > > <parameter param-name="partyId" >>> > > from-field="parameters.partyId"/> >>> > > > </on-event-update-area> >>> > > > </form> >>> > > > >>> > > > If you want to reuse the same form, you need to create another >>> screen >>> > > > with a new form to redefine the on-event-update-area (for instance >>> > > > create a PartyRole). >>> > > > >>> > > > We change the thinking, because since it is the starting context >>> that >>> > > > better knows itself, it's the starting context that will realize >>> the >>> > > > updating operation. The starting context is the screen/menu that >>> call >>> > > > this form. >>> > > > >>> > > > In general a form is contained in a screen (classic) that is called >>> > > > through a link. So we move the idea on this link : >>> > > > >>> > > > <link target="CreatePartyRole" >>> link-type="layered-modal"> >>> > > > <parameter param-name="partyId" >>> > > from-field="customerParty.partyId"/> >>> > > > <update-area area-target="ResumeInfoCustomer" >>> > > area-id="xxx"> >>> > > > <parameter param-name="partyId" >>> > > from-field="customerParty.partyId"/> >>> > > > </update-area> >>> > > > </link> >>> > > > >>> > > > And the form : >>> > > > >>> > > > <form name="EditPartyRole" type="single" >>> > > target="createPartyRole"> >>> > > > <field name="partyId"><hidden/></field> >>> > > > <field name="roleTypeId">... >>> > > > </form> >>> > > > >>> > > > With this logic you can define a new usage of >>> createPartyRole >>> > > > without redefining a form just : >>> > > > >>> > > > <link target="CreatePartyRole" >>> link-type="layered-modal"> >>> > > > <parameter param-name="partyId" >>> > > from-field="partyRelationship.partyIdTo"/> >>> > > > <update-area area-target="MyRelationAndDetail" >>> > > area-id="xxx"> >>> > > > <parameter param-name="partyId" >>> > > from-field="partyRelationship.partyIdTo"/> >>> > > > <parameter param-name="partyRelationTypeId" >>> > > value="IRL_LIKE"/> >>> > > > </update-area> >>> > > > </link> >>> > > > >>> > > > After some use we identified as pro and con feedback : >>> > > > * updating form is reusable and contains only code related to >>> the >>> > > > form action >>> > > > * link being in origin context, the developer knows where he >>> is and >>> > > > where he wants to go >>> > > > * Menu oriented management offers a quick vision on how the >>> screen >>> > > will works >>> > > > >>> > > > * update-area seems to be a too technical name >>> > > > * we always have to manage area to update manually >>> > > > * too many areas to update become a headache and not only for >>> the >>> > > developer >>> > > > >>> > > > We did not explain how we have done it, to try to focus the >>> discussion >>> > > > on the principles. >>> > > > >>> > > > It would be a pleasure to have some criticism of this approach, >>> and we >>> > > > would try, in a second chapter to introduce other concepts that >>> appeared >>> > > > after the screens were made more dynamic and others to lowers the >>> > > > identified cons. >>> > > > >>> > > > Thanks, >>> > > > >>> > > > The Néréide Team >>> > > > >>> > > > [1] https://s.apache.org/rf94 >>> > > > [2] https://s.apache.org/g5zr >>> > > > [3] https://s.apache.org/XpBO >>> > > > [4] https://s.apache.org/YIL1 >>> > > > [5] https://s.apache.org/836D >>> > > > [6] https://s.apache.org/DhyB >>> > > > [7] https://s.apache.org/Lv9E >>> > > > [8] https://s.apache.org/zKIo >>> > > > [9] https://s.apache.org/D6jx >>> > > > >>> > > >>> >> |
In reply to this post by Gavin Mabie-2
Example Angular-Ofbiz formField Service:
import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { of as observableOf,Observable } from 'rxjs'; import { OfbizForm, OfbizFormFieldsBase, OfbizTexboxField, OfbizDisplayField, OfbizDateTimeField, OfbizDropdownField, OfbizHiddenField } from '../Types/ofbiz-forms'; import { tap, map } from 'rxjs/operators'; import { FormControl, Validators, FormGroup } from '@angular/forms'; @Injectable({ providedIn: 'root' }) export class OfbizFormService { baseUrl:string = "https:/***********************************/control/getForm"; constructor(private http: HttpClient) { } getForm(options:any):Observable<any>{ console.log(options); return this.http.get<OfbizForm>(this.baseUrl,options) .pipe( tap(() => console.log('HTTP request executed')), map(resp => resp) ); } toFormGroup(formFields: OfbizFormFieldsBase<any>[]){ let group:any = {}; formFields.forEach(formField => { group[formField.name] = formField.required ? new FormControl(formField.value || '',Validators.required) : new FormControl(formField.value || ''); }); return new FormGroup(group); } getFormFields(rawFields:any[]):Observable<any>{ let fields:OfbizFormFieldsBase<any>[]=[]; rawFields.forEach((field,i) => { let currentValue = null; if(field.value){ currentValue = field.value; }else{ currentValue = field.currentValue; } switch(field.type){ case "hidden": console.log("This is a display"); let hiddenField = new OfbizHiddenField({ key:field.id, label:field.title, value:field.value, name:field.name, order:i, required:field.required, }); fields.push(hiddenField); break; case "display": console.log("This is a display"); let displayfield = new OfbizDisplayField({ key:field.id, label:field.title, value:field.value, name:field.name, order:i, required:field.required, }); fields.push(displayfield); break; case "text": console.log("This is a input"); let textBoxField = new OfbizTexboxField({ key:field.id, label:field.title, value:field.value, name:field.name, order:i, required:field.required, }); fields.push(textBoxField); break; case 'datetime': console.log("This is a input"); let datetimeField = new OfbizDateTimeField({ key:field.id, label:field.title, value:field.value, name:field.name, order:i, required:field.required, }); fields.push(datetimeField); break; case "dropdown": let dropDownField = new OfbizDropdownField({ key:field.id, label:field.title, value:field.value, name:field.name, order:i, required:field.required, options:this.convertOptions(field.allOptionValues), }); fields.push(dropDownField); break; } }); fields.sort((a, b) => a.order - b.order); return observableOf(fields); } convertOptions(allOptionValues:any[]){ let options = []; allOptionValues.forEach(allOptionValue => { let entry = {}; entry['value'] = allOptionValue.key; entry['key'] = allOptionValue.description; options.push(entry); }); return options; } submitForm(form:any,target:string):Observable<any>{ console.log(target); let url:string = "https://***************************"+target; const httpOptions = { headers:new HttpHeaders({ 'Content-Type':'application/json' }) } return this.http.post(url,form,httpOptions) .pipe( map(resp =>resp) ); } } Gavin On Tue, Dec 17, 2019 at 5:18 PM Gavin Mabie <[hidden email]> wrote: > Here's a more complete snippet to get a form - in Groovy. > > if(formLocation) { > String delegatorName = delegator.getDelegatorName(); > if (delegatorName.contains("default#")) { > delegatorName = "default"; > } > DispatchContext dispatchContext = dispatcher.getDispatchContext(); > ModelReader entityModelReader = ModelReader.getModelReader(delegatorName); > ModelForm form = FormFactory.getFormFromLocation(formLocation, formName, > entityModelReader, dispatchContext); > if(form) { > form.runFormActions(context); > target = form.getTarget(context,form.getTargetType()); > targetWindow = form.getTargetWindow(context); > defaultMapName = form.getDefaultMapName(); > > fieldList = form.getFieldList(); > fieldList.each{field -> > } > > for(ModelFormField modelFormField in fieldList) { > ModelFormField.FieldInfo currentFieldInfo = modelFormField.getFieldInfo(); > if (currentFieldInfo != null) { > ModelFormField fieldInfoFormField = currentFieldInfo.getModelFormField(); > if (fieldInfoFormField != null) { > fieldInfoFormField.setModelForm(form); > } > } else { > throw new IllegalArgumentException("Error rendering form, a field has > no FieldInfo, ie no sub-element for the type of field for field named: " + > modelFormField.getName()); > } > > } > > List<ModelFormField> tempFieldList = FastList.newInstance(); > tempFieldList.addAll(fieldList); > //Debug.logInfo("fieldList size: "+form.useWhe+" tempFieldList size: > "+tempFieldList.size(),""); > > for (int j = 0; j < tempFieldList.size(); j++) { > ModelFormField modelFormField = tempFieldList.get(j); > if (form.useWhenFields.contains(modelFormField.getName())) { > boolean shouldUse1 = modelFormField.shouldUse(context); > for (int i = j+1; i < tempFieldList.size(); i++) { > ModelFormField curField = tempFieldList.get(i); > if (curField.getName() != null && > curField.getName().equals(modelFormField.getName())) { > boolean shouldUse2 = curField.shouldUse(context); > if (shouldUse1 == shouldUse2) { > tempFieldList.remove(i--); > } > } else { > continue; > } > } > } > } > Set<String> alreadyRendered = new TreeSet<String>(); > > List<ModelFormField> hiddenIgnoredFieldList = > form.getHiddenIgnoredFields(context, alreadyRendered, tempFieldList, -1); > //renderHiddenIgnoreFields > for(ModelFormField modelFormField in hiddenIgnoredFieldList) { > fieldMap = [:]; > fieldMap.title = modelFormField.getTitle(context); > fieldMap.name = modelFormField.getParameterName(context); > fieldMap.action = modelFormField.getAction(context); > fieldMap.event = modelFormField.getEvent(); > fieldMap.id = modelFormField.getCurrentContainerId(context); > fieldMap.value = modelFormField.getEntry(context); > fieldMap.required = modelFormField.getRequiredField(); > ModelFormField.FieldInfo fieldInfo = modelFormField.getFieldInfo(); > switch(fieldInfo.getFieldType()) { > case ModelFormField.FieldInfo.HIDDEN : > fieldMap.type = "hidden"; > break; > case ModelFormField.FieldInfo.IGNORED : > fieldMap.type = "ignored"; > break; > case ModelFormField.FieldInfo.DISPLAY : > fieldMap.type = "display"; > break; > case ModelFormField.FieldInfo.DISPLAY_ENTITY : > fieldMap.type = "displayEntity"; > break; > case ModelFormField.FieldInfo.HYPERLINK : > fieldMap.type = "hyperlink"; > break; > } > if(fieldInfo.getFieldType() != ModelFormField.FieldInfo.IGNORED) { > fields.add(fieldMap); > } > } > > Iterator<ModelFormField> fieldIter = tempFieldList.iterator(); > ModelFormField lastFormField = null; > ModelFormField currentFormField = null; > ModelFormField nextFormField = null; > if (fieldIter.hasNext()) { > currentFormField = fieldIter.next(); > //ModelFormField.FieldInfo fieldInfo = currentFormField.getFieldInfo(); > //Debug.logInfo("currentFormField : "+currentFormField.getName(),""); > }else { > lastFormField = currentFormField; > currentFormField = null; > } > if (fieldIter.hasNext()) { > nextFormField = fieldIter.next(); > } > while(fieldIter.hasNext()) { > currentFormField = fieldIter.next(); > //Debug.logInfo("currentFormField : "+currentFormField.getName(),""); > ModelFormField.FieldInfo fieldInfo = currentFormField.getFieldInfo(); > if (fieldInfo.getFieldType() == ModelFormField.FieldInfo.HIDDEN || > fieldInfo.getFieldType() == ModelFormField.FieldInfo.IGNORED) { > //Debug.logInfo("continuing : HIDDEN/IGNORED",""); > continue; > } > if (alreadyRendered.contains(currentFormField.getName())) { > //Debug.logInfo("continuing : alreadyRendered",""); > continue; > } > if (!currentFormField.shouldUse(context)) { > if (UtilValidate.isNotEmpty(lastFormField)) { > currentFormField = lastFormField; > } > continue; > } > alreadyRendered.add(currentFormField.getName()); > fieldMap = getFieldMap(fieldInfo,context); > fieldMap.each{key, val -> > } > fields.add(fieldMap); > > } > > } > > } > > Gavin > > On Tue, Dec 17, 2019 at 5:05 PM Gavin Mabie <[hidden email]> wrote: > >> Hi Gil >> >> I used a type=groovy service to resolve the form location eg. >> /* >> *@paramater formLocaction (where the form resides in the system) >> *@parameter formName (passed as request parameter) >> * returns an Ofbiz form entity with all the normal functionalties >> associated with ModelForm >> * this is returned to the http request as a JSON objecct >> */ >> ModelForm form = FormFactory.getFormFromLocation(formLocation, formName, >> entityModelReader, dispatchContext); >> >> Angular handles the response through a formField service which reads each >> Ofbiz formfields (JSON object) and creates a Angular reactive form from >> there. The Angualr formFields Service mirrors the Ofbiz field types etc. >> >> Regards >> >> Gavin >> >> >> >> >> >> >> >> On Tue, Dec 17, 2019 at 4:21 PM Gil Portenseigne < >> [hidden email]> wrote: >> >>> Hello Gavin, >>> >>> Thanks for four feedback, that's very interesting ! >>> >>> Could you elaborate about the OFBiz forms usage you did in your angular >>> implementation ? >>> You just used view-map with simple screen/form ? >>> >>> Cheers ! >>> >>> Gil >>> >>> Le 12:26 - mardi 17 déc., Gavin Mabie a écrit : >>> > Hi Taher >>> > >>> > I've been using Angular for custom apps over the past year. This is my >>> > approach: >>> > >>> > 1. Ofbiz deployed as an AppServer: >>> > 1.1 Ofbiz controller resolves API request calls; >>> > 1.2 Ofbiz Service Engine executes Services; >>> > 1.3 Entity Engine for persistence; >>> > 1.4 Returns JSON object - including Ofbiz context;; >>> > 1.5 Ofbiz Forms used for additional business logic, fields etc; >>> > 1.6 Ofbiz Screens not used at all. >>> > >>> > 2. Angular (On Apache HTTPD or Ionic/Cordova/JQueryMobile or even >>> > JAVAFX(haven't tried this, but it's possible)): >>> > 2.1 Typescripting types for Ofbiz entities used; >>> > 2.2 Angular services for API calls corresponding to controller >>> > request-mappings; >>> > 2.3 Dynamic Angular Forms - based on Ofbiz Form defs; >>> > 2.4 Other static content; >>> > >>> > 3. Authentication >>> > 3.1 With JWT; >>> > 3.2 Sessionless & no cookies; >>> > 3.3 Ofbiz LoginWorker & Permission Engine for authorization; >>> > >>> > The big takeaway here is that Ofbiz Screens aren't used at all. Ofbiz >>> > Forms are used to set fields, execute services and deal with issues >>> like >>> > locale etc. >>> > >>> > Cheers >>> > >>> > gavin >>> > >>> > >>> > >>> > >>> > On Sat, Dec 14, 2019 at 6:52 PM Taher Alkhateeb < >>> [hidden email]> >>> > wrote: >>> > >>> > > Hello Gil, >>> > > >>> > > Great research on the subject, thank you for sharing. >>> > > >>> > > I could be wrong here, but at a first glance it seems you want to >>> > > essentially create a tag "<update-area ..." which essentially renders >>> > > another screen dynamically upon clicking / activating the URL. If my >>> > > understanding is correct, then most likely they way you want to >>> > > implement this is probably some web request to the backend which >>> > > renders back a partial screen that you insert into the DOM right? >>> > > >>> > > If what I describe above is close to your idea, then I think the >>> > > implementation might be relying on the server to do the work of >>> > > painting instead of relying on the browser to do the heavy lifting. >>> > > This also only works with one widget, which is the URL widget as >>> > > opposed to having a general purpose dynamic behavior in the system >>> > > (assuming this is desired). >>> > > >>> > > However, having a general purpose dynamic behavior means we need a >>> > > method to bind variables to values at the front end without >>> consulting >>> > > the back-end. This reduces the load on the server and provides a >>> > > faster / richer experience to the user. But it would be too painful >>> to >>> > > rely on plain javascript or jQuery to achieve such a result which is >>> > > the reason why frameworks like React, Vue, and others emerged as >>> > > modern SPA frameworks. Adopting an SPA framework would provide >>> dynamic >>> > > behavior (everywhere) instead of certain widgets, and it can be >>> > > expanded to even include page navigation and whatnot. Of course this >>> > > is more work than what you're suggesting here. but if we continue >>> with >>> > > such small improvements, you might end up having lots of javascript >>> > > (maybe that's already the case) which might increase the difficulty >>> of >>> > > adopting an SPA framework in the future. >>> > > >>> > > So it comes down to this question (which I don't necessarily have an >>> > > answer to): >>> > > >>> > > Do you want an SPA framework now or in the future, or do you want to >>> > > continue with status quo into the future? If you want an SPA >>> > > framework, then we should minimize the usage of custom javascript >>> > > everywhere and adopt a framework that completely replaces all the >>> > > javascript that currently exists for all the widgets. If not, then we >>> > > can proceed with your proposition and any others in the future >>> knowing >>> > > that an overhaul is not needed. >>> > > >>> > > Cheers, >>> > > >>> > > Taher Alkhateeb >>> > > >>> > > On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne >>> > > <[hidden email]> wrote: >>> > > > >>> > > > Chapter One: How to manage the updating area >>> > > > >>> > > > Hello, >>> > > > >>> > > > After different discussions already listed by Taher [1-9], Leila, >>> > > > Nicolas and me tried another approach. >>> > > > Instead of analyzing how to implement different functionalities >>> offered >>> > > > by modern js framework, we did analyzed how end user use, in >>> general, >>> > > > OFBiz and where we, as an integrator, waste more time to create a >>> > > > screen. >>> > > > >>> > > > To help on this huge task, we set some basic rules : >>> > > > * Work only on screens supported by the theme, defined mainly >>> in xml >>> > > > * This concerns only screens used for back-office applications, >>> > > > oriented to manage data >>> > > > * A developer does not have to know all of js language (or >>> other) >>> > > > but can concentrate on the process/view with the end user to >>> > > > manage a data >>> > > > >>> > > > >>> > > > After a first brainstorm, we have identified three major cases : >>> > > > 1. Navigation and data display >>> > > > 2. View event result (data modification, calculation service, >>> ...) >>> > > > 3. Update an area to refresh data (after data modification) >>> > > > >>> > > > Case 1 and 2 are easy and currently managed by OFBiz (and missing >>> stuff >>> > > > will be simple to add), we concentrate our attention on case 3. >>> > > > >>> > > > To update an area, we follow this pattern >>> > > > >>> > > > 1. We start from a context that display different information >>> > > > >>> > > > 2. That context display a submit form, use a link or another >>> > > > mechanism to call an OFBiz event >>> > > > >>> > > > 3. After receiving the event return, we refresh the desired >>> area >>> > > > with parameters that can come from origin context or from event >>> > > > return. >>> > > > >>> > > > >>> > > > Currently with the screen widget, we can use within a form the >>> element >>> > > > `<on-event-update-area event-type="submit" area-id="" >>> area-target=""/>`. >>> > > > >>> > > > The problem with this use, is that your form needs to know the >>> origin >>> > > > context, to identify what are the areas to update and what are the >>> > > > target to use for the refresh. >>> > > > >>> > > > So your form needs to know where it comes from, what information >>> need to >>> > > > be updated in OFBiz and what will be updated after. >>> > > > >>> > > > This increases complexity for the developer in the way that >>> current form >>> > > > implementation manages : >>> > > > * the data and target to communicate with the server >>> > > > * the behaviour (refreshment) to apply when receiving server >>> response. >>> > > > >>> > > > Example : >>> > > > <form name="EditPartyRoleCustomScreen" type="single" >>> > > target="createPartyRole"> >>> > > > <field name="partyId"><hidden/></field> >>> > > > <field name="roleTypeId">... >>> > > > <on-event-update-area event-type="submit" >>> > > area-id="PartyRoles_area" >>> > > > area-target="PartyRolesCustom"> >>> > > > <parameter param-name="partyId" >>> > > from-field="parameters.partyId"/> >>> > > > </on-event-update-area> >>> > > > </form> >>> > > > >>> > > > If you want to reuse the same form, you need to create another >>> screen >>> > > > with a new form to redefine the on-event-update-area (for instance >>> > > > create a PartyRole). >>> > > > >>> > > > We change the thinking, because since it is the starting context >>> that >>> > > > better knows itself, it's the starting context that will realize >>> the >>> > > > updating operation. The starting context is the screen/menu that >>> call >>> > > > this form. >>> > > > >>> > > > In general a form is contained in a screen (classic) that is called >>> > > > through a link. So we move the idea on this link : >>> > > > >>> > > > <link target="CreatePartyRole" >>> link-type="layered-modal"> >>> > > > <parameter param-name="partyId" >>> > > from-field="customerParty.partyId"/> >>> > > > <update-area area-target="ResumeInfoCustomer" >>> > > area-id="xxx"> >>> > > > <parameter param-name="partyId" >>> > > from-field="customerParty.partyId"/> >>> > > > </update-area> >>> > > > </link> >>> > > > >>> > > > And the form : >>> > > > >>> > > > <form name="EditPartyRole" type="single" >>> > > target="createPartyRole"> >>> > > > <field name="partyId"><hidden/></field> >>> > > > <field name="roleTypeId">... >>> > > > </form> >>> > > > >>> > > > With this logic you can define a new usage of >>> createPartyRole >>> > > > without redefining a form just : >>> > > > >>> > > > <link target="CreatePartyRole" >>> link-type="layered-modal"> >>> > > > <parameter param-name="partyId" >>> > > from-field="partyRelationship.partyIdTo"/> >>> > > > <update-area area-target="MyRelationAndDetail" >>> > > area-id="xxx"> >>> > > > <parameter param-name="partyId" >>> > > from-field="partyRelationship.partyIdTo"/> >>> > > > <parameter param-name="partyRelationTypeId" >>> > > value="IRL_LIKE"/> >>> > > > </update-area> >>> > > > </link> >>> > > > >>> > > > After some use we identified as pro and con feedback : >>> > > > * updating form is reusable and contains only code related to >>> the >>> > > > form action >>> > > > * link being in origin context, the developer knows where he >>> is and >>> > > > where he wants to go >>> > > > * Menu oriented management offers a quick vision on how the >>> screen >>> > > will works >>> > > > >>> > > > * update-area seems to be a too technical name >>> > > > * we always have to manage area to update manually >>> > > > * too many areas to update become a headache and not only for >>> the >>> > > developer >>> > > > >>> > > > We did not explain how we have done it, to try to focus the >>> discussion >>> > > > on the principles. >>> > > > >>> > > > It would be a pleasure to have some criticism of this approach, >>> and we >>> > > > would try, in a second chapter to introduce other concepts that >>> appeared >>> > > > after the screens were made more dynamic and others to lowers the >>> > > > identified cons. >>> > > > >>> > > > Thanks, >>> > > > >>> > > > The Néréide Team >>> > > > >>> > > > [1] https://s.apache.org/rf94 >>> > > > [2] https://s.apache.org/g5zr >>> > > > [3] https://s.apache.org/XpBO >>> > > > [4] https://s.apache.org/YIL1 >>> > > > [5] https://s.apache.org/836D >>> > > > [6] https://s.apache.org/DhyB >>> > > > [7] https://s.apache.org/Lv9E >>> > > > [8] https://s.apache.org/zKIo >>> > > > [9] https://s.apache.org/D6jx >>> > > > >>> > > >>> >> |
In reply to this post by Gavin Mabie-2
Thanks Gavin for sharing, i have a clearer view now :).
Le 17:05 - mardi 17 déc., Gavin Mabie a écrit : > Hi Gil > > I used a type=groovy service to resolve the form location eg. > /* > *@paramater formLocaction (where the form resides in the system) > *@parameter formName (passed as request parameter) > * returns an Ofbiz form entity with all the normal functionalties > associated with ModelForm > * this is returned to the http request as a JSON objecct > */ > ModelForm form = FormFactory.getFormFromLocation(formLocation, formName, > entityModelReader, dispatchContext); > > Angular handles the response through a formField service which reads each > Ofbiz formfields (JSON object) and creates a Angular reactive form from > there. The Angualr formFields Service mirrors the Ofbiz field types etc. > > Regards > > Gavin > > > > > > > > On Tue, Dec 17, 2019 at 4:21 PM Gil Portenseigne < > [hidden email]> wrote: > > > Hello Gavin, > > > > Thanks for four feedback, that's very interesting ! > > > > Could you elaborate about the OFBiz forms usage you did in your angular > > implementation ? > > You just used view-map with simple screen/form ? > > > > Cheers ! > > > > Gil > > > > Le 12:26 - mardi 17 déc., Gavin Mabie a écrit : > > > Hi Taher > > > > > > I've been using Angular for custom apps over the past year. This is my > > > approach: > > > > > > 1. Ofbiz deployed as an AppServer: > > > 1.1 Ofbiz controller resolves API request calls; > > > 1.2 Ofbiz Service Engine executes Services; > > > 1.3 Entity Engine for persistence; > > > 1.4 Returns JSON object - including Ofbiz context;; > > > 1.5 Ofbiz Forms used for additional business logic, fields etc; > > > 1.6 Ofbiz Screens not used at all. > > > > > > 2. Angular (On Apache HTTPD or Ionic/Cordova/JQueryMobile or even > > > JAVAFX(haven't tried this, but it's possible)): > > > 2.1 Typescripting types for Ofbiz entities used; > > > 2.2 Angular services for API calls corresponding to controller > > > request-mappings; > > > 2.3 Dynamic Angular Forms - based on Ofbiz Form defs; > > > 2.4 Other static content; > > > > > > 3. Authentication > > > 3.1 With JWT; > > > 3.2 Sessionless & no cookies; > > > 3.3 Ofbiz LoginWorker & Permission Engine for authorization; > > > > > > The big takeaway here is that Ofbiz Screens aren't used at all. Ofbiz > > > Forms are used to set fields, execute services and deal with issues like > > > locale etc. > > > > > > Cheers > > > > > > gavin > > > > > > > > > > > > > > > On Sat, Dec 14, 2019 at 6:52 PM Taher Alkhateeb < > > [hidden email]> > > > wrote: > > > > > > > Hello Gil, > > > > > > > > Great research on the subject, thank you for sharing. > > > > > > > > I could be wrong here, but at a first glance it seems you want to > > > > essentially create a tag "<update-area ..." which essentially renders > > > > another screen dynamically upon clicking / activating the URL. If my > > > > understanding is correct, then most likely they way you want to > > > > implement this is probably some web request to the backend which > > > > renders back a partial screen that you insert into the DOM right? > > > > > > > > If what I describe above is close to your idea, then I think the > > > > implementation might be relying on the server to do the work of > > > > painting instead of relying on the browser to do the heavy lifting. > > > > This also only works with one widget, which is the URL widget as > > > > opposed to having a general purpose dynamic behavior in the system > > > > (assuming this is desired). > > > > > > > > However, having a general purpose dynamic behavior means we need a > > > > method to bind variables to values at the front end without consulting > > > > the back-end. This reduces the load on the server and provides a > > > > faster / richer experience to the user. But it would be too painful to > > > > rely on plain javascript or jQuery to achieve such a result which is > > > > the reason why frameworks like React, Vue, and others emerged as > > > > modern SPA frameworks. Adopting an SPA framework would provide dynamic > > > > behavior (everywhere) instead of certain widgets, and it can be > > > > expanded to even include page navigation and whatnot. Of course this > > > > is more work than what you're suggesting here. but if we continue with > > > > such small improvements, you might end up having lots of javascript > > > > (maybe that's already the case) which might increase the difficulty of > > > > adopting an SPA framework in the future. > > > > > > > > So it comes down to this question (which I don't necessarily have an > > > > answer to): > > > > > > > > Do you want an SPA framework now or in the future, or do you want to > > > > continue with status quo into the future? If you want an SPA > > > > framework, then we should minimize the usage of custom javascript > > > > everywhere and adopt a framework that completely replaces all the > > > > javascript that currently exists for all the widgets. If not, then we > > > > can proceed with your proposition and any others in the future knowing > > > > that an overhaul is not needed. > > > > > > > > Cheers, > > > > > > > > Taher Alkhateeb > > > > > > > > On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne > > > > <[hidden email]> wrote: > > > > > > > > > > Chapter One: How to manage the updating area > > > > > > > > > > Hello, > > > > > > > > > > After different discussions already listed by Taher [1-9], Leila, > > > > > Nicolas and me tried another approach. > > > > > Instead of analyzing how to implement different functionalities > > offered > > > > > by modern js framework, we did analyzed how end user use, in general, > > > > > OFBiz and where we, as an integrator, waste more time to create a > > > > > screen. > > > > > > > > > > To help on this huge task, we set some basic rules : > > > > > * Work only on screens supported by the theme, defined mainly in > > xml > > > > > * This concerns only screens used for back-office applications, > > > > > oriented to manage data > > > > > * A developer does not have to know all of js language (or other) > > > > > but can concentrate on the process/view with the end user to > > > > > manage a data > > > > > > > > > > > > > > > After a first brainstorm, we have identified three major cases : > > > > > 1. Navigation and data display > > > > > 2. View event result (data modification, calculation service, > > ...) > > > > > 3. Update an area to refresh data (after data modification) > > > > > > > > > > Case 1 and 2 are easy and currently managed by OFBiz (and missing > > stuff > > > > > will be simple to add), we concentrate our attention on case 3. > > > > > > > > > > To update an area, we follow this pattern > > > > > > > > > > 1. We start from a context that display different information > > > > > > > > > > 2. That context display a submit form, use a link or another > > > > > mechanism to call an OFBiz event > > > > > > > > > > 3. After receiving the event return, we refresh the desired area > > > > > with parameters that can come from origin context or from event > > > > > return. > > > > > > > > > > > > > > > Currently with the screen widget, we can use within a form the > > element > > > > > `<on-event-update-area event-type="submit" area-id="" > > area-target=""/>`. > > > > > > > > > > The problem with this use, is that your form needs to know the origin > > > > > context, to identify what are the areas to update and what are the > > > > > target to use for the refresh. > > > > > > > > > > So your form needs to know where it comes from, what information > > need to > > > > > be updated in OFBiz and what will be updated after. > > > > > > > > > > This increases complexity for the developer in the way that current > > form > > > > > implementation manages : > > > > > * the data and target to communicate with the server > > > > > * the behaviour (refreshment) to apply when receiving server > > response. > > > > > > > > > > Example : > > > > > <form name="EditPartyRoleCustomScreen" type="single" > > > > target="createPartyRole"> > > > > > <field name="partyId"><hidden/></field> > > > > > <field name="roleTypeId">... > > > > > <on-event-update-area event-type="submit" > > > > area-id="PartyRoles_area" > > > > > area-target="PartyRolesCustom"> > > > > > <parameter param-name="partyId" > > > > from-field="parameters.partyId"/> > > > > > </on-event-update-area> > > > > > </form> > > > > > > > > > > If you want to reuse the same form, you need to create another screen > > > > > with a new form to redefine the on-event-update-area (for instance > > > > > create a PartyRole). > > > > > > > > > > We change the thinking, because since it is the starting context that > > > > > better knows itself, it's the starting context that will realize the > > > > > updating operation. The starting context is the screen/menu that call > > > > > this form. > > > > > > > > > > In general a form is contained in a screen (classic) that is called > > > > > through a link. So we move the idea on this link : > > > > > > > > > > <link target="CreatePartyRole" link-type="layered-modal"> > > > > > <parameter param-name="partyId" > > > > from-field="customerParty.partyId"/> > > > > > <update-area area-target="ResumeInfoCustomer" > > > > area-id="xxx"> > > > > > <parameter param-name="partyId" > > > > from-field="customerParty.partyId"/> > > > > > </update-area> > > > > > </link> > > > > > > > > > > And the form : > > > > > > > > > > <form name="EditPartyRole" type="single" > > > > target="createPartyRole"> > > > > > <field name="partyId"><hidden/></field> > > > > > <field name="roleTypeId">... > > > > > </form> > > > > > > > > > > With this logic you can define a new usage of createPartyRole > > > > > without redefining a form just : > > > > > > > > > > <link target="CreatePartyRole" link-type="layered-modal"> > > > > > <parameter param-name="partyId" > > > > from-field="partyRelationship.partyIdTo"/> > > > > > <update-area area-target="MyRelationAndDetail" > > > > area-id="xxx"> > > > > > <parameter param-name="partyId" > > > > from-field="partyRelationship.partyIdTo"/> > > > > > <parameter param-name="partyRelationTypeId" > > > > value="IRL_LIKE"/> > > > > > </update-area> > > > > > </link> > > > > > > > > > > After some use we identified as pro and con feedback : > > > > > * updating form is reusable and contains only code related to the > > > > > form action > > > > > * link being in origin context, the developer knows where he is > > and > > > > > where he wants to go > > > > > * Menu oriented management offers a quick vision on how the > > screen > > > > will works > > > > > > > > > > * update-area seems to be a too technical name > > > > > * we always have to manage area to update manually > > > > > * too many areas to update become a headache and not only for the > > > > developer > > > > > > > > > > We did not explain how we have done it, to try to focus the > > discussion > > > > > on the principles. > > > > > > > > > > It would be a pleasure to have some criticism of this approach, and > > we > > > > > would try, in a second chapter to introduce other concepts that > > appeared > > > > > after the screens were made more dynamic and others to lowers the > > > > > identified cons. > > > > > > > > > > Thanks, > > > > > > > > > > The Néréide Team > > > > > > > > > > [1] https://s.apache.org/rf94 > > > > > [2] https://s.apache.org/g5zr > > > > > [3] https://s.apache.org/XpBO > > > > > [4] https://s.apache.org/YIL1 > > > > > [5] https://s.apache.org/836D > > > > > [6] https://s.apache.org/DhyB > > > > > [7] https://s.apache.org/Lv9E > > > > > [8] https://s.apache.org/zKIo > > > > > [9] https://s.apache.org/D6jx > > > > > > > > > > > |
Administrator
|
Thanks indeed Gavin for all the details,
I guess others have also implemented solutions with SPA frameworks. It would be interesting to compare the implementations... Thanks Jacques Le 17/12/2019 à 21:11, Gil Portenseigne a écrit : > Thanks Gavin for sharing, i have a clearer view now :). > > Le 17:05 - mardi 17 déc., Gavin Mabie a écrit : >> Hi Gil >> >> I used a type=groovy service to resolve the form location eg. >> /* >> *@paramater formLocaction (where the form resides in the system) >> *@parameter formName (passed as request parameter) >> * returns an Ofbiz form entity with all the normal functionalties >> associated with ModelForm >> * this is returned to the http request as a JSON objecct >> */ >> ModelForm form = FormFactory.getFormFromLocation(formLocation, formName, >> entityModelReader, dispatchContext); >> >> Angular handles the response through a formField service which reads each >> Ofbiz formfields (JSON object) and creates a Angular reactive form from >> there. The Angualr formFields Service mirrors the Ofbiz field types etc. >> >> Regards >> >> Gavin >> >> >> >> >> >> >> >> On Tue, Dec 17, 2019 at 4:21 PM Gil Portenseigne < >> [hidden email]> wrote: >> >>> Hello Gavin, >>> >>> Thanks for four feedback, that's very interesting ! >>> >>> Could you elaborate about the OFBiz forms usage you did in your angular >>> implementation ? >>> You just used view-map with simple screen/form ? >>> >>> Cheers ! >>> >>> Gil >>> >>> Le 12:26 - mardi 17 déc., Gavin Mabie a écrit : >>>> Hi Taher >>>> >>>> I've been using Angular for custom apps over the past year. This is my >>>> approach: >>>> >>>> 1. Ofbiz deployed as an AppServer: >>>> 1.1 Ofbiz controller resolves API request calls; >>>> 1.2 Ofbiz Service Engine executes Services; >>>> 1.3 Entity Engine for persistence; >>>> 1.4 Returns JSON object - including Ofbiz context;; >>>> 1.5 Ofbiz Forms used for additional business logic, fields etc; >>>> 1.6 Ofbiz Screens not used at all. >>>> >>>> 2. Angular (On Apache HTTPD or Ionic/Cordova/JQueryMobile or even >>>> JAVAFX(haven't tried this, but it's possible)): >>>> 2.1 Typescripting types for Ofbiz entities used; >>>> 2.2 Angular services for API calls corresponding to controller >>>> request-mappings; >>>> 2.3 Dynamic Angular Forms - based on Ofbiz Form defs; >>>> 2.4 Other static content; >>>> >>>> 3. Authentication >>>> 3.1 With JWT; >>>> 3.2 Sessionless & no cookies; >>>> 3.3 Ofbiz LoginWorker & Permission Engine for authorization; >>>> >>>> The big takeaway here is that Ofbiz Screens aren't used at all. Ofbiz >>>> Forms are used to set fields, execute services and deal with issues like >>>> locale etc. >>>> >>>> Cheers >>>> >>>> gavin >>>> >>>> >>>> >>>> >>>> On Sat, Dec 14, 2019 at 6:52 PM Taher Alkhateeb < >>> [hidden email]> >>>> wrote: >>>> >>>>> Hello Gil, >>>>> >>>>> Great research on the subject, thank you for sharing. >>>>> >>>>> I could be wrong here, but at a first glance it seems you want to >>>>> essentially create a tag "<update-area ..." which essentially renders >>>>> another screen dynamically upon clicking / activating the URL. If my >>>>> understanding is correct, then most likely they way you want to >>>>> implement this is probably some web request to the backend which >>>>> renders back a partial screen that you insert into the DOM right? >>>>> >>>>> If what I describe above is close to your idea, then I think the >>>>> implementation might be relying on the server to do the work of >>>>> painting instead of relying on the browser to do the heavy lifting. >>>>> This also only works with one widget, which is the URL widget as >>>>> opposed to having a general purpose dynamic behavior in the system >>>>> (assuming this is desired). >>>>> >>>>> However, having a general purpose dynamic behavior means we need a >>>>> method to bind variables to values at the front end without consulting >>>>> the back-end. This reduces the load on the server and provides a >>>>> faster / richer experience to the user. But it would be too painful to >>>>> rely on plain javascript or jQuery to achieve such a result which is >>>>> the reason why frameworks like React, Vue, and others emerged as >>>>> modern SPA frameworks. Adopting an SPA framework would provide dynamic >>>>> behavior (everywhere) instead of certain widgets, and it can be >>>>> expanded to even include page navigation and whatnot. Of course this >>>>> is more work than what you're suggesting here. but if we continue with >>>>> such small improvements, you might end up having lots of javascript >>>>> (maybe that's already the case) which might increase the difficulty of >>>>> adopting an SPA framework in the future. >>>>> >>>>> So it comes down to this question (which I don't necessarily have an >>>>> answer to): >>>>> >>>>> Do you want an SPA framework now or in the future, or do you want to >>>>> continue with status quo into the future? If you want an SPA >>>>> framework, then we should minimize the usage of custom javascript >>>>> everywhere and adopt a framework that completely replaces all the >>>>> javascript that currently exists for all the widgets. If not, then we >>>>> can proceed with your proposition and any others in the future knowing >>>>> that an overhaul is not needed. >>>>> >>>>> Cheers, >>>>> >>>>> Taher Alkhateeb >>>>> >>>>> On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne >>>>> <[hidden email]> wrote: >>>>>> Chapter One: How to manage the updating area >>>>>> >>>>>> Hello, >>>>>> >>>>>> After different discussions already listed by Taher [1-9], Leila, >>>>>> Nicolas and me tried another approach. >>>>>> Instead of analyzing how to implement different functionalities >>> offered >>>>>> by modern js framework, we did analyzed how end user use, in general, >>>>>> OFBiz and where we, as an integrator, waste more time to create a >>>>>> screen. >>>>>> >>>>>> To help on this huge task, we set some basic rules : >>>>>> * Work only on screens supported by the theme, defined mainly in >>> xml >>>>>> * This concerns only screens used for back-office applications, >>>>>> oriented to manage data >>>>>> * A developer does not have to know all of js language (or other) >>>>>> but can concentrate on the process/view with the end user to >>>>>> manage a data >>>>>> >>>>>> >>>>>> After a first brainstorm, we have identified three major cases : >>>>>> 1. Navigation and data display >>>>>> 2. View event result (data modification, calculation service, >>> ...) >>>>>> 3. Update an area to refresh data (after data modification) >>>>>> >>>>>> Case 1 and 2 are easy and currently managed by OFBiz (and missing >>> stuff >>>>>> will be simple to add), we concentrate our attention on case 3. >>>>>> >>>>>> To update an area, we follow this pattern >>>>>> >>>>>> 1. We start from a context that display different information >>>>>> >>>>>> 2. That context display a submit form, use a link or another >>>>>> mechanism to call an OFBiz event >>>>>> >>>>>> 3. After receiving the event return, we refresh the desired area >>>>>> with parameters that can come from origin context or from event >>>>>> return. >>>>>> >>>>>> >>>>>> Currently with the screen widget, we can use within a form the >>> element >>>>>> `<on-event-update-area event-type="submit" area-id="" >>> area-target=""/>`. >>>>>> The problem with this use, is that your form needs to know the origin >>>>>> context, to identify what are the areas to update and what are the >>>>>> target to use for the refresh. >>>>>> >>>>>> So your form needs to know where it comes from, what information >>> need to >>>>>> be updated in OFBiz and what will be updated after. >>>>>> >>>>>> This increases complexity for the developer in the way that current >>> form >>>>>> implementation manages : >>>>>> * the data and target to communicate with the server >>>>>> * the behaviour (refreshment) to apply when receiving server >>> response. >>>>>> Example : >>>>>> <form name="EditPartyRoleCustomScreen" type="single" >>>>> target="createPartyRole"> >>>>>> <field name="partyId"><hidden/></field> >>>>>> <field name="roleTypeId">... >>>>>> <on-event-update-area event-type="submit" >>>>> area-id="PartyRoles_area" >>>>>> area-target="PartyRolesCustom"> >>>>>> <parameter param-name="partyId" >>>>> from-field="parameters.partyId"/> >>>>>> </on-event-update-area> >>>>>> </form> >>>>>> >>>>>> If you want to reuse the same form, you need to create another screen >>>>>> with a new form to redefine the on-event-update-area (for instance >>>>>> create a PartyRole). >>>>>> >>>>>> We change the thinking, because since it is the starting context that >>>>>> better knows itself, it's the starting context that will realize the >>>>>> updating operation. The starting context is the screen/menu that call >>>>>> this form. >>>>>> >>>>>> In general a form is contained in a screen (classic) that is called >>>>>> through a link. So we move the idea on this link : >>>>>> >>>>>> <link target="CreatePartyRole" link-type="layered-modal"> >>>>>> <parameter param-name="partyId" >>>>> from-field="customerParty.partyId"/> >>>>>> <update-area area-target="ResumeInfoCustomer" >>>>> area-id="xxx"> >>>>>> <parameter param-name="partyId" >>>>> from-field="customerParty.partyId"/> >>>>>> </update-area> >>>>>> </link> >>>>>> >>>>>> And the form : >>>>>> >>>>>> <form name="EditPartyRole" type="single" >>>>> target="createPartyRole"> >>>>>> <field name="partyId"><hidden/></field> >>>>>> <field name="roleTypeId">... >>>>>> </form> >>>>>> >>>>>> With this logic you can define a new usage of createPartyRole >>>>>> without redefining a form just : >>>>>> >>>>>> <link target="CreatePartyRole" link-type="layered-modal"> >>>>>> <parameter param-name="partyId" >>>>> from-field="partyRelationship.partyIdTo"/> >>>>>> <update-area area-target="MyRelationAndDetail" >>>>> area-id="xxx"> >>>>>> <parameter param-name="partyId" >>>>> from-field="partyRelationship.partyIdTo"/> >>>>>> <parameter param-name="partyRelationTypeId" >>>>> value="IRL_LIKE"/> >>>>>> </update-area> >>>>>> </link> >>>>>> >>>>>> After some use we identified as pro and con feedback : >>>>>> * updating form is reusable and contains only code related to the >>>>>> form action >>>>>> * link being in origin context, the developer knows where he is >>> and >>>>>> where he wants to go >>>>>> * Menu oriented management offers a quick vision on how the >>> screen >>>>> will works >>>>>> * update-area seems to be a too technical name >>>>>> * we always have to manage area to update manually >>>>>> * too many areas to update become a headache and not only for the >>>>> developer >>>>>> We did not explain how we have done it, to try to focus the >>> discussion >>>>>> on the principles. >>>>>> >>>>>> It would be a pleasure to have some criticism of this approach, and >>> we >>>>>> would try, in a second chapter to introduce other concepts that >>> appeared >>>>>> after the screens were made more dynamic and others to lowers the >>>>>> identified cons. >>>>>> >>>>>> Thanks, >>>>>> >>>>>> The Néréide Team >>>>>> >>>>>> [1] https://s.apache.org/rf94 >>>>>> [2] https://s.apache.org/g5zr >>>>>> [3] https://s.apache.org/XpBO >>>>>> [4] https://s.apache.org/YIL1 >>>>>> [5] https://s.apache.org/836D >>>>>> [6] https://s.apache.org/DhyB >>>>>> [7] https://s.apache.org/Lv9E >>>>>> [8] https://s.apache.org/zKIo >>>>>> [9] https://s.apache.org/D6jx >>>>>> |
In reply to this post by Gavin Mabie-2
Hi Gavin,
Separation completely GUI and application could be exploring, but I think it will be in a future step. Currently, one of step which can easily be done is having API for all services already used by the screen, (the future POST, PUT, PATCH and DELETE) be able to call them without a screen as return flow, return flow will be only success or error and messages associated Maybe a controller file could be dedicated by component with these URI. I supposed , you have done something similar for your Angular custom app, for the POC-VueJS it's needed. Separation completely GUI from application needed too, to be able to have GET to read data, to know which data to send in which context, and currently it's, most of time, executed/filtered by screen/forms. Realize a complete new set of API for GET using logic used by screen/form (security / display-entity, ...) will be a very large task and I think it will be better to work on using screen/form and having a correct rendering data on a intermediate step. Difficulties to have a correct data rendering is : When rendering, as JSON flow, for some "field", it's not easily to say what is only data, what is user presentation data. I will try to explain by some example : 1) field with hyperlink, * only data is clear it's description, but when it's a image the data is more the image logical name (edit / remove / deactivate ...) * hyperlink parameters : I think it's data but on the data sent is it sub-data of fieldName or data at the same level 2) field display, * red-when is it data ? * format, if it exist, data should be with format used or not 3) required attribute : is it data I think it is possible to decide for each what is the choice of the community but as a intermediate step send a little more data is a solution too ;-) In the POC-VueJs, we have decided to send screen/form tag and attributes, this gives the user/SPA-GUI-developer the choice Olivier PS: Many thanks for your questions / remarks, they helped me to see things more clearly, and to decide the points to continue to study or where to go for the next step. Le 17/12/2019 à 12:28, Gavin Mabie a écrit : > Hi Oliver > > I think separating the GUI completely from the application layer could be > an option worthy of exploring. That would mean api requests and with > standard responses in JSON or XML. What the end user does with the > response is entirely up to him/her. In this scenario the responses and > their shapes are highly structured leaving the chosen GUI framework up to > the user. Not easy as business/workflow processes would have to be > represented by well defined api endpoints. Although the current view > renderer accommodates abstraction for different view implementations it > only really result in HTML in the end. > > Your question: is it clever to have same functionality with the multiple > renderer? > My response: don't have a view renderer at all. > > What do you think? > > Gavin > > > On Tue, Dec 17, 2019 at 12:22 PM Olivier Heintz <[hidden email]> wrote: > >> Hello Taher, >> >>> Do you want an SPA framework now or in the future, >> is a very important question but >> which road to use to go is important too. >> >> As with the current gui renderer architecture, it's possible to have >> multiple rendrer engine for the "same" screen/menu/form xml files, >> one question is : is it clever to have same functionality with the >> multiple renderer ? >> maybe the html should be oriented low-technology approach, and so no >> javascript or minimum (in futur) >> the SPA should oriented multi-device and "modern" approach >> >> In all case evolution can be step by step and having clear xml formal >> expression for user interaction is good. >> >> With POC-VueJs we wanted to answerd to the question : is it possible to >> have screen/menu/form xml files AND SPA renderer with all advantage of SPA. >> Currently, answer is clearly Yes. >> Our choices or codes are maybe not correct but it's not with a lot of >> workaround to be able to say it works. >> Some value are bind on the front end and when back-end is consulted, value >> in front end are updated and so screen are updated. >> (one more time, our code is only a demonstration code to help to find the >> goods one) >> >> 80-20 rule is always true, with SPA too >> so I'm really confident than 80% of xml screen/menu/form can be renderer >> with a SPA and having a very good SPA advantage usage. >> For the 20%, it will need to have dedicated SPA component, and during >> "migration" process which screen should be in 20% will be discuss. >> >> Olivier >> >> >> >> Le 14/12/2019 à 17:51, Taher Alkhateeb a écrit : >>> Hello Gil, >>> >>> Great research on the subject, thank you for sharing. >>> >>> I could be wrong here, but at a first glance it seems you want to >>> essentially create a tag "<update-area ..." which essentially renders >>> another screen dynamically upon clicking / activating the URL. If my >>> understanding is correct, then most likely they way you want to >>> implement this is probably some web request to the backend which >>> renders back a partial screen that you insert into the DOM right? >>> >>> If what I describe above is close to your idea, then I think the >>> implementation might be relying on the server to do the work of >>> painting instead of relying on the browser to do the heavy lifting. >>> This also only works with one widget, which is the URL widget as >>> opposed to having a general purpose dynamic behavior in the system >>> (assuming this is desired). >>> >>> However, having a general purpose dynamic behavior means we need a >>> method to bind variables to values at the front end without consulting >>> the back-end. This reduces the load on the server and provides a >>> faster / richer experience to the user. But it would be too painful to >>> rely on plain javascript or jQuery to achieve such a result which is >>> the reason why frameworks like React, Vue, and others emerged as >>> modern SPA frameworks. Adopting an SPA framework would provide dynamic >>> behavior (everywhere) instead of certain widgets, and it can be >>> expanded to even include page navigation and whatnot. Of course this >>> is more work than what you're suggesting here. but if we continue with >>> such small improvements, you might end up having lots of javascript >>> (maybe that's already the case) which might increase the difficulty of >>> adopting an SPA framework in the future. >>> >>> So it comes down to this question (which I don't necessarily have an >> answer to): >>> >>> Do you want an SPA framework now or in the future, or do you want to >>> continue with status quo into the future? If you want an SPA >>> framework, then we should minimize the usage of custom javascript >>> everywhere and adopt a framework that completely replaces all the >>> javascript that currently exists for all the widgets. If not, then we >>> can proceed with your proposition and any others in the future knowing >>> that an overhaul is not needed. >>> >>> Cheers, >>> >>> Taher Alkhateeb >>> >>> On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne >>> <[hidden email]> wrote: >>>> >>>> Chapter One: How to manage the updating area >>>> >>>> Hello, >>>> >>>> After different discussions already listed by Taher [1-9], Leila, >>>> Nicolas and me tried another approach. >>>> Instead of analyzing how to implement different functionalities offered >>>> by modern js framework, we did analyzed how end user use, in general, >>>> OFBiz and where we, as an integrator, waste more time to create a >>>> screen. >>>> >>>> To help on this huge task, we set some basic rules : >>>> * Work only on screens supported by the theme, defined mainly in xml >>>> * This concerns only screens used for back-office applications, >>>> oriented to manage data >>>> * A developer does not have to know all of js language (or other) >>>> but can concentrate on the process/view with the end user to >>>> manage a data >>>> >>>> >>>> After a first brainstorm, we have identified three major cases : >>>> 1. Navigation and data display >>>> 2. View event result (data modification, calculation service, ...) >>>> 3. Update an area to refresh data (after data modification) >>>> >>>> Case 1 and 2 are easy and currently managed by OFBiz (and missing stuff >>>> will be simple to add), we concentrate our attention on case 3. >>>> >>>> To update an area, we follow this pattern >>>> >>>> 1. We start from a context that display different information >>>> >>>> 2. That context display a submit form, use a link or another >>>> mechanism to call an OFBiz event >>>> >>>> 3. After receiving the event return, we refresh the desired area >>>> with parameters that can come from origin context or from event >>>> return. >>>> >>>> >>>> Currently with the screen widget, we can use within a form the element >>>> `<on-event-update-area event-type="submit" area-id="" area-target=""/>`. >>>> >>>> The problem with this use, is that your form needs to know the origin >>>> context, to identify what are the areas to update and what are the >>>> target to use for the refresh. >>>> >>>> So your form needs to know where it comes from, what information need to >>>> be updated in OFBiz and what will be updated after. >>>> >>>> This increases complexity for the developer in the way that current form >>>> implementation manages : >>>> * the data and target to communicate with the server >>>> * the behaviour (refreshment) to apply when receiving server response. >>>> >>>> Example : >>>> <form name="EditPartyRoleCustomScreen" type="single" >> target="createPartyRole"> >>>> <field name="partyId"><hidden/></field> >>>> <field name="roleTypeId">... >>>> <on-event-update-area event-type="submit" >> area-id="PartyRoles_area" >>>> area-target="PartyRolesCustom"> >>>> <parameter param-name="partyId" >> from-field="parameters.partyId"/> >>>> </on-event-update-area> >>>> </form> >>>> >>>> If you want to reuse the same form, you need to create another screen >>>> with a new form to redefine the on-event-update-area (for instance >>>> create a PartyRole). >>>> >>>> We change the thinking, because since it is the starting context that >>>> better knows itself, it's the starting context that will realize the >>>> updating operation. The starting context is the screen/menu that call >>>> this form. >>>> >>>> In general a form is contained in a screen (classic) that is called >>>> through a link. So we move the idea on this link : >>>> >>>> <link target="CreatePartyRole" link-type="layered-modal"> >>>> <parameter param-name="partyId" >> from-field="customerParty.partyId"/> >>>> <update-area area-target="ResumeInfoCustomer" >> area-id="xxx"> >>>> <parameter param-name="partyId" >> from-field="customerParty.partyId"/> >>>> </update-area> >>>> </link> >>>> >>>> And the form : >>>> >>>> <form name="EditPartyRole" type="single" >> target="createPartyRole"> >>>> <field name="partyId"><hidden/></field> >>>> <field name="roleTypeId">... >>>> </form> >>>> >>>> With this logic you can define a new usage of createPartyRole >>>> without redefining a form just : >>>> >>>> <link target="CreatePartyRole" link-type="layered-modal"> >>>> <parameter param-name="partyId" >> from-field="partyRelationship.partyIdTo"/> >>>> <update-area area-target="MyRelationAndDetail" >> area-id="xxx"> >>>> <parameter param-name="partyId" >> from-field="partyRelationship.partyIdTo"/> >>>> <parameter param-name="partyRelationTypeId" >> value="IRL_LIKE"/> >>>> </update-area> >>>> </link> >>>> >>>> After some use we identified as pro and con feedback : >>>> * updating form is reusable and contains only code related to the >>>> form action >>>> * link being in origin context, the developer knows where he is and >>>> where he wants to go >>>> * Menu oriented management offers a quick vision on how the screen >> will works >>>> >>>> * update-area seems to be a too technical name >>>> * we always have to manage area to update manually >>>> * too many areas to update become a headache and not only for the >> developer >>>> >>>> We did not explain how we have done it, to try to focus the discussion >>>> on the principles. >>>> >>>> It would be a pleasure to have some criticism of this approach, and we >>>> would try, in a second chapter to introduce other concepts that appeared >>>> after the screens were made more dynamic and others to lowers the >>>> identified cons. >>>> >>>> Thanks, >>>> >>>> The Néréide Team >>>> >>>> [1] https://s.apache.org/rf94 >>>> [2] https://s.apache.org/g5zr >>>> [3] https://s.apache.org/XpBO >>>> [4] https://s.apache.org/YIL1 >>>> [5] https://s.apache.org/836D >>>> [6] https://s.apache.org/DhyB >>>> [7] https://s.apache.org/Lv9E >>>> [8] https://s.apache.org/zKIo >>>> [9] https://s.apache.org/D6jx >>>> >> > |
Thanks Olivier
You said: When rendering, as JSON flow, for some "field", it's not easily to say what is only data, what is user presentation data. Here's a JSON response for A EditPerson Form: { "target": "createClient", "targetWindow": "", "fields": [ { "title": "Role Type Id", "name": "roleTypeId", "event": "", "id": "EditPerson_roleTypeId", "value": "HOMEINIT_CLIENT", "required": false, "type": "hidden" }, { "title": "First Name", "name": "firstName", "value": "", "id": "EditPerson_firstName", "required": true, "type": "text" }, { "title": "Last Name", "name": "lastName", "value": "", "id": "EditPerson_lastName", "required": true, "type": "text" }, { "title": "Gender", "name": "gender", "value": "", "id": "EditPerson_gender", "required": false, "type": "dropdown", "allOptionValues": [ { "key": "M", "description": "Male" }, { "key": "F", "description": "Female" } ], "textSize": 0 }, { "title": "Birth Date", "name": "birthDate", "value": "", "id": "EditPerson_birthDate", "required": false, "type": "datetime" }, { "title": "Height", "name": "height", "value": "", "id": "EditPerson_height", "event": "", "required": false, "type": "text" }, { "title": "Weight", "name": "weight", "value": "", "id": "EditPerson_weight", "event": "", "required": false, "type": "text" }, { "title": "Marital Status", "name": "maritalStatus", "value": "", "id": "EditPerson_maritalStatus", "event": "", "required": false, "type": "dropdown", "allOptionValues": [ { "key": "S", "description": "Single" }, { "key": "M", "description": "Married" }, { "key": "P", "description": "Separated" }, { "key": "D", "description": "Divorced" }, { "key": "W", "description": "Widowed" } ], "textSize": 0 }, { "title": "RSA ID", "name": "socialSecurityNumber", "value": "", "id": "EditPerson_socialSecurityNumber", "required": false, "type": "text" }, { "title": "Passport Number", "name": "passportNumber", "value": "", "id": "EditPerson_passportNumber", "required": false, "type": "text" }, { "title": "Employment Status Enum Id", "name": "employmentStatusEnumId", "value": "", "id": "EditPerson_employmentStatusEnumId", "event": "", "required": false, "type": "dropdown", "allOptionValues": [ { "key": "EMPS_FULLTIME", "description": "Full-time Employed [FULLTIME]" }, { "key": "EMPS_PARTTIME", "description": "Part-time Employed [PARTTIME]" }, { "key": "EMPS_SELF", "description": "Self Employed [SELF]" }, { "key": "EMPS_HOUSE", "description": "House-Person [HOUSE]" }, { "key": "EMPS_RETIRED", "description": "Retired [RETIRED]" }, { "key": "EMPS_STUDENT", "description": "Student [STUDENT]" }, { "key": "EMPS_UNEMP", "description": "Unemployed [UNEMP]" } ], "textSize": 0 }, { "title": "Residence Status Enum Id", "name": "residenceStatusEnumId", "value": "", "id": "EditPerson_residenceStatusEnumId", "event": "", "required": false, "type": "dropdown", "allOptionValues": [ { "key": "PRESS_OWN", "description": "Own Home [OWN]" }, { "key": "PRESS_PVT_TENANT", "description": "Private Tenant [PVT_TENANT]" }, { "key": "PRESS_PUB_TENANT", "description": "Public Tenant [PUB_TENANT]" }, { "key": "PRESS_PARENTS", "description": "With Parents [PARENTS]" } ], "textSize": 0 }, { "title": "Status ID", "name": "statusId", "value": "", "id": "EditPerson_statusId", "required": false, "type": "text" }, { "title": "Save", "name": "submitButton", "value": "", "id": "EditPerson_submitButton", "event": "", "required": false }, { "title": " ", "name": "cancelLink", "value": "", "id": "EditPerson_cancelLink", "event": "", "required": false } ] } All the fields and their attributes generated by Ofbiz are included in the JSON response. Good luck with you POC. Cheers Gavin On Fri, Dec 20, 2019 at 4:10 PM Olivier Heintz <[hidden email]> wrote: > Hi Gavin, > > Separation completely GUI and application could be exploring, but I think > it will be in a future step. > > Currently, one of step which can easily be done is having API for all > services already used by the screen, (the future POST, PUT, PATCH and > DELETE) > be able to call them without a screen as return flow, return flow will be > only success or error and messages associated > Maybe a controller file could be dedicated by component with these URI. > I supposed , you have done something similar for your Angular custom app, > for the POC-VueJS it's needed. > > Separation completely GUI from application needed too, to be able to have > GET to read data, to know which data to send in which context, and currently > it's, most of time, executed/filtered by screen/forms. > Realize a complete new set of API for GET using logic used by screen/form > (security / display-entity, ...) will be a very large task and I think it > will be better to work on using screen/form and having a correct rendering > data on a intermediate step. > Difficulties to have a correct data rendering is : > When rendering, as JSON flow, for some "field", it's not easily to say > what is only data, what is user presentation data. I will try to explain by > some example : > 1) field with hyperlink, > * only data is clear it's description, but when it's a image the data is > more the image logical name (edit / remove / deactivate ...) > * hyperlink parameters : I think it's data but on the data sent is it > sub-data of fieldName or data at the same level > 2) field display, > * red-when is it data ? > * format, if it exist, data should be with format used or not > 3) required attribute : is it data > > I think it is possible to decide for each what is the choice of the > community but as a intermediate step send a little more data is a solution > too ;-) > > In the POC-VueJs, we have decided to send screen/form tag and attributes, > this gives the user/SPA-GUI-developer the choice > > Olivier > > PS: Many thanks for your questions / remarks, they helped me to see things > more clearly, and to decide the points to continue to study or where to go > for the next step. > > > Le 17/12/2019 à 12:28, Gavin Mabie a écrit : > > Hi Oliver > > > > I think separating the GUI completely from the application layer could be > > an option worthy of exploring. That would mean api requests and with > > standard responses in JSON or XML. What the end user does with the > > response is entirely up to him/her. In this scenario the responses and > > their shapes are highly structured leaving the chosen GUI framework up to > > the user. Not easy as business/workflow processes would have to be > > represented by well defined api endpoints. Although the current view > > renderer accommodates abstraction for different view implementations it > > only really result in HTML in the end. > > > > Your question: is it clever to have same functionality with the multiple > > renderer? > > My response: don't have a view renderer at all. > > > > What do you think? > > > > Gavin > > > > > > On Tue, Dec 17, 2019 at 12:22 PM Olivier Heintz <[hidden email]> > wrote: > > > >> Hello Taher, > >> > >>> Do you want an SPA framework now or in the future, > >> is a very important question but > >> which road to use to go is important too. > >> > >> As with the current gui renderer architecture, it's possible to have > >> multiple rendrer engine for the "same" screen/menu/form xml files, > >> one question is : is it clever to have same functionality with the > >> multiple renderer ? > >> maybe the html should be oriented low-technology approach, and so no > >> javascript or minimum (in futur) > >> the SPA should oriented multi-device and "modern" approach > >> > >> In all case evolution can be step by step and having clear xml formal > >> expression for user interaction is good. > >> > >> With POC-VueJs we wanted to answerd to the question : is it possible to > >> have screen/menu/form xml files AND SPA renderer with all advantage of > SPA. > >> Currently, answer is clearly Yes. > >> Our choices or codes are maybe not correct but it's not with a lot of > >> workaround to be able to say it works. > >> Some value are bind on the front end and when back-end is consulted, > value > >> in front end are updated and so screen are updated. > >> (one more time, our code is only a demonstration code to help to find > the > >> goods one) > >> > >> 80-20 rule is always true, with SPA too > >> so I'm really confident than 80% of xml screen/menu/form can be renderer > >> with a SPA and having a very good SPA advantage usage. > >> For the 20%, it will need to have dedicated SPA component, and during > >> "migration" process which screen should be in 20% will be discuss. > >> > >> Olivier > >> > >> > >> > >> Le 14/12/2019 à 17:51, Taher Alkhateeb a écrit : > >>> Hello Gil, > >>> > >>> Great research on the subject, thank you for sharing. > >>> > >>> I could be wrong here, but at a first glance it seems you want to > >>> essentially create a tag "<update-area ..." which essentially renders > >>> another screen dynamically upon clicking / activating the URL. If my > >>> understanding is correct, then most likely they way you want to > >>> implement this is probably some web request to the backend which > >>> renders back a partial screen that you insert into the DOM right? > >>> > >>> If what I describe above is close to your idea, then I think the > >>> implementation might be relying on the server to do the work of > >>> painting instead of relying on the browser to do the heavy lifting. > >>> This also only works with one widget, which is the URL widget as > >>> opposed to having a general purpose dynamic behavior in the system > >>> (assuming this is desired). > >>> > >>> However, having a general purpose dynamic behavior means we need a > >>> method to bind variables to values at the front end without consulting > >>> the back-end. This reduces the load on the server and provides a > >>> faster / richer experience to the user. But it would be too painful to > >>> rely on plain javascript or jQuery to achieve such a result which is > >>> the reason why frameworks like React, Vue, and others emerged as > >>> modern SPA frameworks. Adopting an SPA framework would provide dynamic > >>> behavior (everywhere) instead of certain widgets, and it can be > >>> expanded to even include page navigation and whatnot. Of course this > >>> is more work than what you're suggesting here. but if we continue with > >>> such small improvements, you might end up having lots of javascript > >>> (maybe that's already the case) which might increase the difficulty of > >>> adopting an SPA framework in the future. > >>> > >>> So it comes down to this question (which I don't necessarily have an > >> answer to): > >>> > >>> Do you want an SPA framework now or in the future, or do you want to > >>> continue with status quo into the future? If you want an SPA > >>> framework, then we should minimize the usage of custom javascript > >>> everywhere and adopt a framework that completely replaces all the > >>> javascript that currently exists for all the widgets. If not, then we > >>> can proceed with your proposition and any others in the future knowing > >>> that an overhaul is not needed. > >>> > >>> Cheers, > >>> > >>> Taher Alkhateeb > >>> > >>> On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne > >>> <[hidden email]> wrote: > >>>> > >>>> Chapter One: How to manage the updating area > >>>> > >>>> Hello, > >>>> > >>>> After different discussions already listed by Taher [1-9], Leila, > >>>> Nicolas and me tried another approach. > >>>> Instead of analyzing how to implement different functionalities > offered > >>>> by modern js framework, we did analyzed how end user use, in general, > >>>> OFBiz and where we, as an integrator, waste more time to create a > >>>> screen. > >>>> > >>>> To help on this huge task, we set some basic rules : > >>>> * Work only on screens supported by the theme, defined mainly in > xml > >>>> * This concerns only screens used for back-office applications, > >>>> oriented to manage data > >>>> * A developer does not have to know all of js language (or other) > >>>> but can concentrate on the process/view with the end user to > >>>> manage a data > >>>> > >>>> > >>>> After a first brainstorm, we have identified three major cases : > >>>> 1. Navigation and data display > >>>> 2. View event result (data modification, calculation service, ...) > >>>> 3. Update an area to refresh data (after data modification) > >>>> > >>>> Case 1 and 2 are easy and currently managed by OFBiz (and missing > stuff > >>>> will be simple to add), we concentrate our attention on case 3. > >>>> > >>>> To update an area, we follow this pattern > >>>> > >>>> 1. We start from a context that display different information > >>>> > >>>> 2. That context display a submit form, use a link or another > >>>> mechanism to call an OFBiz event > >>>> > >>>> 3. After receiving the event return, we refresh the desired area > >>>> with parameters that can come from origin context or from event > >>>> return. > >>>> > >>>> > >>>> Currently with the screen widget, we can use within a form the element > >>>> `<on-event-update-area event-type="submit" area-id="" > area-target=""/>`. > >>>> > >>>> The problem with this use, is that your form needs to know the origin > >>>> context, to identify what are the areas to update and what are the > >>>> target to use for the refresh. > >>>> > >>>> So your form needs to know where it comes from, what information need > to > >>>> be updated in OFBiz and what will be updated after. > >>>> > >>>> This increases complexity for the developer in the way that current > form > >>>> implementation manages : > >>>> * the data and target to communicate with the server > >>>> * the behaviour (refreshment) to apply when receiving server > response. > >>>> > >>>> Example : > >>>> <form name="EditPartyRoleCustomScreen" type="single" > >> target="createPartyRole"> > >>>> <field name="partyId"><hidden/></field> > >>>> <field name="roleTypeId">... > >>>> <on-event-update-area event-type="submit" > >> area-id="PartyRoles_area" > >>>> area-target="PartyRolesCustom"> > >>>> <parameter param-name="partyId" > >> from-field="parameters.partyId"/> > >>>> </on-event-update-area> > >>>> </form> > >>>> > >>>> If you want to reuse the same form, you need to create another screen > >>>> with a new form to redefine the on-event-update-area (for instance > >>>> create a PartyRole). > >>>> > >>>> We change the thinking, because since it is the starting context that > >>>> better knows itself, it's the starting context that will realize the > >>>> updating operation. The starting context is the screen/menu that call > >>>> this form. > >>>> > >>>> In general a form is contained in a screen (classic) that is called > >>>> through a link. So we move the idea on this link : > >>>> > >>>> <link target="CreatePartyRole" link-type="layered-modal"> > >>>> <parameter param-name="partyId" > >> from-field="customerParty.partyId"/> > >>>> <update-area area-target="ResumeInfoCustomer" > >> area-id="xxx"> > >>>> <parameter param-name="partyId" > >> from-field="customerParty.partyId"/> > >>>> </update-area> > >>>> </link> > >>>> > >>>> And the form : > >>>> > >>>> <form name="EditPartyRole" type="single" > >> target="createPartyRole"> > >>>> <field name="partyId"><hidden/></field> > >>>> <field name="roleTypeId">... > >>>> </form> > >>>> > >>>> With this logic you can define a new usage of createPartyRole > >>>> without redefining a form just : > >>>> > >>>> <link target="CreatePartyRole" link-type="layered-modal"> > >>>> <parameter param-name="partyId" > >> from-field="partyRelationship.partyIdTo"/> > >>>> <update-area area-target="MyRelationAndDetail" > >> area-id="xxx"> > >>>> <parameter param-name="partyId" > >> from-field="partyRelationship.partyIdTo"/> > >>>> <parameter param-name="partyRelationTypeId" > >> value="IRL_LIKE"/> > >>>> </update-area> > >>>> </link> > >>>> > >>>> After some use we identified as pro and con feedback : > >>>> * updating form is reusable and contains only code related to the > >>>> form action > >>>> * link being in origin context, the developer knows where he is > and > >>>> where he wants to go > >>>> * Menu oriented management offers a quick vision on how the screen > >> will works > >>>> > >>>> * update-area seems to be a too technical name > >>>> * we always have to manage area to update manually > >>>> * too many areas to update become a headache and not only for the > >> developer > >>>> > >>>> We did not explain how we have done it, to try to focus the discussion > >>>> on the principles. > >>>> > >>>> It would be a pleasure to have some criticism of this approach, and we > >>>> would try, in a second chapter to introduce other concepts that > appeared > >>>> after the screens were made more dynamic and others to lowers the > >>>> identified cons. > >>>> > >>>> Thanks, > >>>> > >>>> The Néréide Team > >>>> > >>>> [1] https://s.apache.org/rf94 > >>>> [2] https://s.apache.org/g5zr > >>>> [3] https://s.apache.org/XpBO > >>>> [4] https://s.apache.org/YIL1 > >>>> [5] https://s.apache.org/836D > >>>> [6] https://s.apache.org/DhyB > >>>> [7] https://s.apache.org/Lv9E > >>>> [8] https://s.apache.org/zKIo > >>>> [9] https://s.apache.org/D6jx > >>>> > >> > > > |
In reply to this post by Gil Portenseigne
Le 17/12/2019 à 15:12, Gil Portenseigne a écrit : > Hello Taher, > > The proposition you saw with your first glance is ..... > > In that vision implementing a theme for SPA application should be > possible, but in our opinion a gigantic task to support the screen > engine. We think that for back office application, we should stay with > the classic way to implement screens, and improve it to get more > efficient. > The implementation of a theme for a SPA application is a big task and should be studied from an agile perspective. POC-VueJs was initiated and realized in this perspective. The POC should allow to : * to be able to test a simple conversion from macro.ftl to the vuejs component (or other SPA framework) * be able to test the advanced functionalities of the SPA framework from the point of view of an ERP back office application * to be able to test new uses of the graphical interface linked to the SPA concept I think this is only possible if there are enough screens / components available in the POC. We chose Party because it will be possible to derive it to HR / CRM B2C / eCommerce Profile pages / CRM B2B / facilities workers. Currently, only the main screens of Party are working, it is possible to play with them at https://ofbiz-selenium.ofbizextra.org/partymgrfjs/control/main (vuejs is in dev mode so it is possible to view components and store areas) https://demo-vuejs.ofbizextra.org/partymgrfjs/control/main (vuejs is in prod mode) POC-VueJs is not a theme but there are already very similar points and we should work in this direction too. Even if some modifications should be made on a component before using this "kind of theme", we should consider rendering it - component VueJs as a theme. POC will have several steps before it is possible to choose and validate the right solutions. During POC we store the "migration time" per component / screens to be able to have an evaluation of the migration ofbiz applications in the future. |
In reply to this post by Gavin Mabie-2
Hi Gavin,
Clearly, our POC json response for EditPerson is much more verbose :-) Your example show us that it's possible to reduce number of level in hierarchy ;-) When I work on documentation/comment/javadoc JsonRenderer, I review what attribute is really use / usable and so I remove some. In one or two month, it will be better { "viewScreenName":"EditPerson", "viewEntities":{}, "viewScreen":[ { "name":"Form", "attributes":{ "viewSize":20, "formType":"single", "autocomplete":"", "containerStyle":"", "viewIndex":0, "focusFieldName":"salutation", "useRowSubmit":false, "entityName":"", "hasRequiredField":"Y", "linkUrl":"/partymgrfjs/control/updatePerson", "name":"EditPerson", "containerId":"EditPerson", "viewSizeField":"viewSize_0", "viewIndexField":"viewIndex_0", "targetWindow":""}}]} "children":[ { "name":"HiddenField", "attributes":{ "conditionGroup":"", "formName":"EditPerson", "name":"partyId", "id":"EditPerson_partyId", "event":"", "value":"sfa101" } }, { "name":"SingleWrapper", "attributes":{ "formName":"EditPerson", "style":"basic-table" } "children":[ { "name":"FieldRow", "attributes":{} "children":[ { "name":"FieldRowTitleCell", "attributes":{} }, { "name":"FieldRowWidgetCell", "attributes":{ "positionSpan":1, "style":"" } "children":[ { "name":"DisplayField", "attributes":{ "idName":"EditPerson_partyId", "alert":"true", "formName":"EditPerson", "name":"partyId", "description":"sfa101", "type":"text" } }] }] }, { "name":"FieldRow", "attributes":{} "children":[ { "name":"FieldRowTitleCell", "attributes":{} "children":[ { "name":"FieldTitle", "attributes":{ "fieldHelpText":"", "for":"EditPerson_partyId", "style":"", "id":"EditPerson_partyId", "title":"Party ID" } }] }, { "name":"FieldRowWidgetCell", "attributes":{ "positionSpan":1, "style":"" } "children":[ { "name":"TextField", "attributes":{ "textSize":40, "maxlength":60, "clientAutocomplete":"true", "required":{ "requiredField":"false", "requiredStyle":"" }, "ajaxEnabled":true, "delegatorName":"default", "readonly":false, "alert":"false", "formName":"EditPerson", "name":"salutation", "disabled":false, "id":"EditPerson_salutation", "value":"" } }] }] }, { "name":"FieldRow", "attributes":{} "children":[ { "name":"FieldRowTitleCell", "attributes":{} "children":[ { "name":"FieldTitle", "attributes":{ "fieldHelpText":"", "for":"EditPerson_firstName", "style":"", "id":"EditPerson_firstName", "title":"Party ID" } }] }, { "name":"FieldRowWidgetCell", "attributes":{ "positionSpan":1, "style":"" } "children":[ { "name":"TextField", "attributes":{ "textSize":40, "maxlength":60, "className:"required" "clientAutocomplete":"true", "required":{ "requiredField":"true", "requiredStyle":"" }, "ajaxEnabled":true, "delegatorName":"default", "readonly":false, "alert":"false", "formName":"EditPerson", "name":"firstName", "disabled":false, "id":"EditPerson_firstName", "value":"John" } }] }] }, { .... Le 20/12/2019 à 16:22, Gavin Mabie a écrit : > Thanks Olivier > > You said: When rendering, as JSON flow, for some "field", it's not easily > to say what is only data, what is user presentation data. > > Here's a JSON response for A EditPerson Form: > { > "target": "createClient", > "targetWindow": "", > "fields": [ > { > "title": "Role Type Id", > "name": "roleTypeId", > "event": "", > "id": "EditPerson_roleTypeId", > "value": "HOMEINIT_CLIENT", > "required": false, > "type": "hidden" > }, > { > "title": "First Name", > "name": "firstName", > "value": "", > "id": "EditPerson_firstName", > "required": true, > "type": "text" > }, > { > "title": "Last Name", > "name": "lastName", > "value": "", > "id": "EditPerson_lastName", > "required": true, > "type": "text" > }, > { > "title": "Gender", > "name": "gender", > "value": "", > "id": "EditPerson_gender", > "required": false, > "type": "dropdown", > "allOptionValues": [ > { > "key": "M", > "description": "Male" > }, > { > "key": "F", > "description": "Female" > } > ], > "textSize": 0 > }, > { > "title": "Birth Date", > "name": "birthDate", > "value": "", > "id": "EditPerson_birthDate", > "required": false, > "type": "datetime" > }, > { > "title": "Height", > "name": "height", > "value": "", > "id": "EditPerson_height", > "event": "", > "required": false, > "type": "text" > }, > { > "title": "Weight", > "name": "weight", > "value": "", > "id": "EditPerson_weight", > "event": "", > "required": false, > "type": "text" > }, > { > "title": "Marital Status", > "name": "maritalStatus", > "value": "", > "id": "EditPerson_maritalStatus", > "event": "", > "required": false, > "type": "dropdown", > "allOptionValues": [ > { > "key": "S", > "description": "Single" > }, > { > "key": "M", > "description": "Married" > }, > { > "key": "P", > "description": "Separated" > }, > { > "key": "D", > "description": "Divorced" > }, > { > "key": "W", > "description": "Widowed" > } > ], > "textSize": 0 > }, > { > "title": "RSA ID", > "name": "socialSecurityNumber", > "value": "", > "id": "EditPerson_socialSecurityNumber", > "required": false, > "type": "text" > }, > { > "title": "Passport Number", > "name": "passportNumber", > "value": "", > "id": "EditPerson_passportNumber", > "required": false, > "type": "text" > }, > { > "title": "Employment Status Enum Id", > "name": "employmentStatusEnumId", > "value": "", > "id": "EditPerson_employmentStatusEnumId", > "event": "", > "required": false, > "type": "dropdown", > "allOptionValues": [ > { > "key": "EMPS_FULLTIME", > "description": "Full-time Employed [FULLTIME]" > }, > { > "key": "EMPS_PARTTIME", > "description": "Part-time Employed [PARTTIME]" > }, > { > "key": "EMPS_SELF", > "description": "Self Employed [SELF]" > }, > { > "key": "EMPS_HOUSE", > "description": "House-Person [HOUSE]" > }, > { > "key": "EMPS_RETIRED", > "description": "Retired [RETIRED]" > }, > { > "key": "EMPS_STUDENT", > "description": "Student [STUDENT]" > }, > { > "key": "EMPS_UNEMP", > "description": "Unemployed [UNEMP]" > } > ], > "textSize": 0 > }, > { > "title": "Residence Status Enum Id", > "name": "residenceStatusEnumId", > "value": "", > "id": "EditPerson_residenceStatusEnumId", > "event": "", > "required": false, > "type": "dropdown", > "allOptionValues": [ > { > "key": "PRESS_OWN", > "description": "Own Home [OWN]" > }, > { > "key": "PRESS_PVT_TENANT", > "description": "Private Tenant [PVT_TENANT]" > }, > { > "key": "PRESS_PUB_TENANT", > "description": "Public Tenant [PUB_TENANT]" > }, > { > "key": "PRESS_PARENTS", > "description": "With Parents [PARENTS]" > } > ], > "textSize": 0 > }, > { > "title": "Status ID", > "name": "statusId", > "value": "", > "id": "EditPerson_statusId", > "required": false, > "type": "text" > }, > { > "title": "Save", > "name": "submitButton", > "value": "", > "id": "EditPerson_submitButton", > "event": "", > "required": false > }, > { > "title": " ", > "name": "cancelLink", > "value": "", > "id": "EditPerson_cancelLink", > "event": "", > "required": false > } > ] > } > > All the fields and their attributes generated by Ofbiz are included in the > JSON response. > > Good luck with you POC. > > Cheers > > Gavin > > > > On Fri, Dec 20, 2019 at 4:10 PM Olivier Heintz <[hidden email]> wrote: > >> Hi Gavin, >> >> Separation completely GUI and application could be exploring, but I think >> it will be in a future step. >> >> Currently, one of step which can easily be done is having API for all >> services already used by the screen, (the future POST, PUT, PATCH and >> DELETE) >> be able to call them without a screen as return flow, return flow will be >> only success or error and messages associated >> Maybe a controller file could be dedicated by component with these URI. >> I supposed , you have done something similar for your Angular custom app, >> for the POC-VueJS it's needed. >> >> Separation completely GUI from application needed too, to be able to have >> GET to read data, to know which data to send in which context, and currently >> it's, most of time, executed/filtered by screen/forms. >> Realize a complete new set of API for GET using logic used by screen/form >> (security / display-entity, ...) will be a very large task and I think it >> will be better to work on using screen/form and having a correct rendering >> data on a intermediate step. >> Difficulties to have a correct data rendering is : >> When rendering, as JSON flow, for some "field", it's not easily to say >> what is only data, what is user presentation data. I will try to explain by >> some example : >> 1) field with hyperlink, >> * only data is clear it's description, but when it's a image the data is >> more the image logical name (edit / remove / deactivate ...) >> * hyperlink parameters : I think it's data but on the data sent is it >> sub-data of fieldName or data at the same level >> 2) field display, >> * red-when is it data ? >> * format, if it exist, data should be with format used or not >> 3) required attribute : is it data >> >> I think it is possible to decide for each what is the choice of the >> community but as a intermediate step send a little more data is a solution >> too ;-) >> >> In the POC-VueJs, we have decided to send screen/form tag and attributes, >> this gives the user/SPA-GUI-developer the choice >> >> Olivier >> >> PS: Many thanks for your questions / remarks, they helped me to see things >> more clearly, and to decide the points to continue to study or where to go >> for the next step. >> >> >> Le 17/12/2019 à 12:28, Gavin Mabie a écrit : >>> Hi Oliver >>> >>> I think separating the GUI completely from the application layer could be >>> an option worthy of exploring. That would mean api requests and with >>> standard responses in JSON or XML. What the end user does with the >>> response is entirely up to him/her. In this scenario the responses and >>> their shapes are highly structured leaving the chosen GUI framework up to >>> the user. Not easy as business/workflow processes would have to be >>> represented by well defined api endpoints. Although the current view >>> renderer accommodates abstraction for different view implementations it >>> only really result in HTML in the end. >>> >>> Your question: is it clever to have same functionality with the multiple >>> renderer? >>> My response: don't have a view renderer at all. >>> >>> What do you think? >>> >>> Gavin >>> >>> >>> On Tue, Dec 17, 2019 at 12:22 PM Olivier Heintz <[hidden email]> >> wrote: >>> >>>> Hello Taher, >>>> >>>>> Do you want an SPA framework now or in the future, >>>> is a very important question but >>>> which road to use to go is important too. >>>> >>>> As with the current gui renderer architecture, it's possible to have >>>> multiple rendrer engine for the "same" screen/menu/form xml files, >>>> one question is : is it clever to have same functionality with the >>>> multiple renderer ? >>>> maybe the html should be oriented low-technology approach, and so no >>>> javascript or minimum (in futur) >>>> the SPA should oriented multi-device and "modern" approach >>>> >>>> In all case evolution can be step by step and having clear xml formal >>>> expression for user interaction is good. >>>> >>>> With POC-VueJs we wanted to answerd to the question : is it possible to >>>> have screen/menu/form xml files AND SPA renderer with all advantage of >> SPA. >>>> Currently, answer is clearly Yes. >>>> Our choices or codes are maybe not correct but it's not with a lot of >>>> workaround to be able to say it works. >>>> Some value are bind on the front end and when back-end is consulted, >> value >>>> in front end are updated and so screen are updated. >>>> (one more time, our code is only a demonstration code to help to find >> the >>>> goods one) >>>> >>>> 80-20 rule is always true, with SPA too >>>> so I'm really confident than 80% of xml screen/menu/form can be renderer >>>> with a SPA and having a very good SPA advantage usage. >>>> For the 20%, it will need to have dedicated SPA component, and during >>>> "migration" process which screen should be in 20% will be discuss. >>>> >>>> Olivier >>>> >>>> >>>> >>>> Le 14/12/2019 à 17:51, Taher Alkhateeb a écrit : >>>>> Hello Gil, >>>>> >>>>> Great research on the subject, thank you for sharing. >>>>> >>>>> I could be wrong here, but at a first glance it seems you want to >>>>> essentially create a tag "<update-area ..." which essentially renders >>>>> another screen dynamically upon clicking / activating the URL. If my >>>>> understanding is correct, then most likely they way you want to >>>>> implement this is probably some web request to the backend which >>>>> renders back a partial screen that you insert into the DOM right? >>>>> >>>>> If what I describe above is close to your idea, then I think the >>>>> implementation might be relying on the server to do the work of >>>>> painting instead of relying on the browser to do the heavy lifting. >>>>> This also only works with one widget, which is the URL widget as >>>>> opposed to having a general purpose dynamic behavior in the system >>>>> (assuming this is desired). >>>>> >>>>> However, having a general purpose dynamic behavior means we need a >>>>> method to bind variables to values at the front end without consulting >>>>> the back-end. This reduces the load on the server and provides a >>>>> faster / richer experience to the user. But it would be too painful to >>>>> rely on plain javascript or jQuery to achieve such a result which is >>>>> the reason why frameworks like React, Vue, and others emerged as >>>>> modern SPA frameworks. Adopting an SPA framework would provide dynamic >>>>> behavior (everywhere) instead of certain widgets, and it can be >>>>> expanded to even include page navigation and whatnot. Of course this >>>>> is more work than what you're suggesting here. but if we continue with >>>>> such small improvements, you might end up having lots of javascript >>>>> (maybe that's already the case) which might increase the difficulty of >>>>> adopting an SPA framework in the future. >>>>> >>>>> So it comes down to this question (which I don't necessarily have an >>>> answer to): >>>>> >>>>> Do you want an SPA framework now or in the future, or do you want to >>>>> continue with status quo into the future? If you want an SPA >>>>> framework, then we should minimize the usage of custom javascript >>>>> everywhere and adopt a framework that completely replaces all the >>>>> javascript that currently exists for all the widgets. If not, then we >>>>> can proceed with your proposition and any others in the future knowing >>>>> that an overhaul is not needed. >>>>> >>>>> Cheers, >>>>> >>>>> Taher Alkhateeb >>>>> >>>>> On Fri, Dec 13, 2019 at 6:52 PM Gil Portenseigne >>>>> <[hidden email]> wrote: >>>>>> >>>>>> Chapter One: How to manage the updating area >>>>>> >>>>>> Hello, >>>>>> >>>>>> After different discussions already listed by Taher [1-9], Leila, >>>>>> Nicolas and me tried another approach. >>>>>> Instead of analyzing how to implement different functionalities >> offered >>>>>> by modern js framework, we did analyzed how end user use, in general, >>>>>> OFBiz and where we, as an integrator, waste more time to create a >>>>>> screen. >>>>>> >>>>>> To help on this huge task, we set some basic rules : >>>>>> * Work only on screens supported by the theme, defined mainly in >> xml >>>>>> * This concerns only screens used for back-office applications, >>>>>> oriented to manage data >>>>>> * A developer does not have to know all of js language (or other) >>>>>> but can concentrate on the process/view with the end user to >>>>>> manage a data >>>>>> >>>>>> >>>>>> After a first brainstorm, we have identified three major cases : >>>>>> 1. Navigation and data display >>>>>> 2. View event result (data modification, calculation service, ...) >>>>>> 3. Update an area to refresh data (after data modification) >>>>>> >>>>>> Case 1 and 2 are easy and currently managed by OFBiz (and missing >> stuff >>>>>> will be simple to add), we concentrate our attention on case 3. >>>>>> >>>>>> To update an area, we follow this pattern >>>>>> >>>>>> 1. We start from a context that display different information >>>>>> >>>>>> 2. That context display a submit form, use a link or another >>>>>> mechanism to call an OFBiz event >>>>>> >>>>>> 3. After receiving the event return, we refresh the desired area >>>>>> with parameters that can come from origin context or from event >>>>>> return. >>>>>> >>>>>> >>>>>> Currently with the screen widget, we can use within a form the element >>>>>> `<on-event-update-area event-type="submit" area-id="" >> area-target=""/>`. >>>>>> >>>>>> The problem with this use, is that your form needs to know the origin >>>>>> context, to identify what are the areas to update and what are the >>>>>> target to use for the refresh. >>>>>> >>>>>> So your form needs to know where it comes from, what information need >> to >>>>>> be updated in OFBiz and what will be updated after. >>>>>> >>>>>> This increases complexity for the developer in the way that current >> form >>>>>> implementation manages : >>>>>> * the data and target to communicate with the server >>>>>> * the behaviour (refreshment) to apply when receiving server >> response. >>>>>> >>>>>> Example : >>>>>> <form name="EditPartyRoleCustomScreen" type="single" >>>> target="createPartyRole"> >>>>>> <field name="partyId"><hidden/></field> >>>>>> <field name="roleTypeId">... >>>>>> <on-event-update-area event-type="submit" >>>> area-id="PartyRoles_area" >>>>>> area-target="PartyRolesCustom"> >>>>>> <parameter param-name="partyId" >>>> from-field="parameters.partyId"/> >>>>>> </on-event-update-area> >>>>>> </form> >>>>>> >>>>>> If you want to reuse the same form, you need to create another screen >>>>>> with a new form to redefine the on-event-update-area (for instance >>>>>> create a PartyRole). >>>>>> >>>>>> We change the thinking, because since it is the starting context that >>>>>> better knows itself, it's the starting context that will realize the >>>>>> updating operation. The starting context is the screen/menu that call >>>>>> this form. >>>>>> >>>>>> In general a form is contained in a screen (classic) that is called >>>>>> through a link. So we move the idea on this link : >>>>>> >>>>>> <link target="CreatePartyRole" link-type="layered-modal"> >>>>>> <parameter param-name="partyId" >>>> from-field="customerParty.partyId"/> >>>>>> <update-area area-target="ResumeInfoCustomer" >>>> area-id="xxx"> >>>>>> <parameter param-name="partyId" >>>> from-field="customerParty.partyId"/> >>>>>> </update-area> >>>>>> </link> >>>>>> >>>>>> And the form : >>>>>> >>>>>> <form name="EditPartyRole" type="single" >>>> target="createPartyRole"> >>>>>> <field name="partyId"><hidden/></field> >>>>>> <field name="roleTypeId">... >>>>>> </form> >>>>>> >>>>>> With this logic you can define a new usage of createPartyRole >>>>>> without redefining a form just : >>>>>> >>>>>> <link target="CreatePartyRole" link-type="layered-modal"> >>>>>> <parameter param-name="partyId" >>>> from-field="partyRelationship.partyIdTo"/> >>>>>> <update-area area-target="MyRelationAndDetail" >>>> area-id="xxx"> >>>>>> <parameter param-name="partyId" >>>> from-field="partyRelationship.partyIdTo"/> >>>>>> <parameter param-name="partyRelationTypeId" >>>> value="IRL_LIKE"/> >>>>>> </update-area> >>>>>> </link> >>>>>> >>>>>> After some use we identified as pro and con feedback : >>>>>> * updating form is reusable and contains only code related to the >>>>>> form action >>>>>> * link being in origin context, the developer knows where he is >> and >>>>>> where he wants to go >>>>>> * Menu oriented management offers a quick vision on how the screen >>>> will works >>>>>> >>>>>> * update-area seems to be a too technical name >>>>>> * we always have to manage area to update manually >>>>>> * too many areas to update become a headache and not only for the >>>> developer >>>>>> >>>>>> We did not explain how we have done it, to try to focus the discussion >>>>>> on the principles. >>>>>> >>>>>> It would be a pleasure to have some criticism of this approach, and we >>>>>> would try, in a second chapter to introduce other concepts that >> appeared >>>>>> after the screens were made more dynamic and others to lowers the >>>>>> identified cons. >>>>>> >>>>>> Thanks, >>>>>> >>>>>> The Néréide Team >>>>>> >>>>>> [1] https://s.apache.org/rf94 >>>>>> [2] https://s.apache.org/g5zr >>>>>> [3] https://s.apache.org/XpBO >>>>>> [4] https://s.apache.org/YIL1 >>>>>> [5] https://s.apache.org/836D >>>>>> [6] https://s.apache.org/DhyB >>>>>> [7] https://s.apache.org/Lv9E >>>>>> [8] https://s.apache.org/zKIo >>>>>> [9] https://s.apache.org/D6jx >>>>>> >>>> >>> >> > |
In reply to this post by holivier
Hi Olivier
Quick question: Are you using NodeJs & NPM in your POC? And if so are you integrating with Gradle? Cheers Gavin On Mon, Dec 23, 2019 at 6:33 PM Olivier Heintz <[hidden email]> wrote: > > > Le 17/12/2019 à 15:12, Gil Portenseigne a écrit : > > Hello Taher, > > > > The proposition you saw with your first glance is > ..... > > > > > In that vision implementing a theme for SPA application should be > > possible, but in our opinion a gigantic task to support the screen > > engine. We think that for back office application, we should stay with > > the classic way to implement screens, and improve it to get more > > efficient. > > > > The implementation of a theme for a SPA application is a big task and > should be studied from an agile perspective. > POC-VueJs was initiated and realized in this perspective. > The POC should allow to : > * to be able to test a simple conversion from macro.ftl to the vuejs > component (or other SPA framework) > * be able to test the advanced functionalities of the SPA framework from > the point of view of an ERP back office application > * to be able to test new uses of the graphical interface linked to the > SPA concept > > I think this is only possible if there are enough screens / components > available in the POC. > We chose Party because it will be possible to derive it to HR / CRM B2C / > eCommerce Profile pages / CRM B2B / facilities workers. > Currently, only the main screens of Party are working, it is possible to > play with them at > https://ofbiz-selenium.ofbizextra.org/partymgrfjs/control/main (vuejs is > in dev mode so it is possible to view components and store areas) > https://demo-vuejs.ofbizextra.org/partymgrfjs/control/main (vuejs is in > prod mode) > > POC-VueJs is not a theme but there are already very similar points and we > should work in this direction too. > Even if some modifications should be made on a component before using this > "kind of theme", we should consider rendering it - component VueJs as a > theme. > > POC will have several steps before it is possible to choose and validate > the right solutions. > During POC we store the "migration time" per component / screens to be > able to have an evaluation of the migration ofbiz applications in the > future. > > |
very quick answer (inline)
Best Regards Le 08/01/2020 à 17:39, Gavin Mabie a écrit : > Hi Olivier > > Quick question: Are you using NodeJs & NPM in your POC? yes And if so are you > integrating with Gradle? Not yet > > Cheers > > Gavin > |
Free forum by Nabble | Edit this page |