none
Lightswitch HTML - afterApplyChanges event

    Question

  • Hi,

    I need to call a function to refresh data after the data on an Edit screen is updated (i.e., I need a function "afterApplyChanges"). I know that Lightswitch HTML has a beforeApplyChanges function. How can I implement a function "afterApplyChanges"?

    Thanks!

    Wednesday, July 24, 2013 8:10 PM

Answers

  • I found a solution by hacking the code in /Scripts/datajs-1.1.0.min. There is a function called "stt" (stt = function (n, t, i)) at line 14 column 67381. That function is called AFTER the changes are saved to the database. I defined a custom function "myapp.ChangesSaved" and in the function "stt" I call that function. 

    Not the cleanest solution. However, it gets me what I need for the current time. I'm certainly open to other solutions.

    • Marked as answer by Abdulla16 Thursday, July 25, 2013 10:01 PM
    Thursday, July 25, 2013 10:01 PM

All replies

  • Oh, so close....but the LS team went with myapp.onsavechanges instead of afterApplyChanges after a long and protracted battle about what to call this function.

    See Customize the Save command to save to multiple data sources for a usage example.


    Wednesday, July 24, 2013 8:49 PM
  • Thanks for your reply!

    But it looks like onsavechanges is called BEFORE saving the data to the database. I need a function that will get called AFTER the data is saved to the database. 

    Thursday, July 25, 2013 4:59 AM
  • I found a solution by hacking the code in /Scripts/datajs-1.1.0.min. There is a function called "stt" (stt = function (n, t, i)) at line 14 column 67381. That function is called AFTER the changes are saved to the database. I defined a custom function "myapp.ChangesSaved" and in the function "stt" I call that function. 

    Not the cleanest solution. However, it gets me what I need for the current time. I'm certainly open to other solutions.

    • Marked as answer by Abdulla16 Thursday, July 25, 2013 10:01 PM
    Thursday, July 25, 2013 10:01 PM
  • That approach sounds highly suspect and is not recommended.

    You didn't give much detail of what you were trying to achieve, so offering other solutions is also sketchy.  If you had wanted to trigger a function after an item is saved in the database, you have all of the existing server procedures in the save pipeline (Entity_Inserted, Entity_Updated, SaveChanges_Executed) as well as the JavaScript and LightSwitch API methods .addEventListener("collectionchange", listener), or .addChangeListener() to trigger a function when data is saved.

    Friday, July 26, 2013 4:39 AM
  • .addEventListener("collectionchange", listener), or .addChangeListener() didn't work for me as they already get fired on changing the fieldvalue itself and not after saving it to the database. Or do we have to add the event listener to another collection as the screen collection (screen.SomeCollectionItems)?

    I think he tries the same as me to get some computed value from the server, which doesn't get updated on client side after saving. The problem is on a second save of the entity the client checks the current values of the database before saving it and as they are different to the chached one of the client it throws a transaction exeption as it thinks the data has changed from another person since last saving.

    So the solution was to reload the collection/entity to get the current values after saving it.

    Friday, July 26, 2013 10:53 AM
  • Please see:

    New API For Refreshing Data in LightSwitch in Visual Studio 2013

    The new refresh() API consists of  two methods that each return a Promise object.

    • refresh()      
      • Asynchronously loads the first page of items into this collection and           
        returns a promise that will be fulfilled when the first page is loaded.            
        Existing results will be refreshed on the first page and subsequent            
        pages unless load() is called again.
    • refresh(navigationPropertyNames)      
      • Updates the entity with values from the data source if the entity           
        is not changed.
                  
        • <param name="navigationPropertyNames" type="Array" optional="true">                
          An array of names of navigation properties to be included. An empty                
          array means no properties will be included. If not specified, all                
          reference properties are included.

    Sample usage

    • Refresh the Order entity and its Customer, Employee, Shipper      
      • screen.Order.details.refresh();
    • Refresh only the Order entity      
      • screen.Order.details.refresh([]);
    • Refresh the Order entity and its Customer      
      • screen.Order.details.refresh(["Customer"]);

    Unleash the Power - Get the LightSwitch HTML Client book

    http://LightSwitchHelpWebsite.com

    Friday, July 26, 2013 1:08 PM
  • There is also the

    msls.NavigateBackAction.commit || cancel

    property for determining save versus cancel from a recently closed screen.

    Friday, July 26, 2013 2:37 PM
  • Hi Abdulla16,

    You can implement BeforeSave and AfterSave like this:

    myapp.onsavechanges = function (e) {

        // BEFORE SAVE

        var ent = myapp.activeDataWorkspace.ApplicationData.Table1Items.addNew()

        ent.s = "added before, will be saved";

        e.detail.promise = myapp.activeDataWorkspace.ApplicationData.saveChanges().then(function (e) {

            // AFTER SAVE

            var ent2 = myapp.activeDataWorkspace.ApplicationData.Table1Items.addNew();

            ent2.s = "added after, won't be saved";

        });

    Regards,

    Burt

    Wednesday, November 20, 2013 11:51 PM
  • Hello, I am trying to implement this code in LS 2013, but falling a bit flat. This is what my code looks like, with a little detail up front:

    My Browse Screen is called BrowseOrderLines.lsml

    My Edit screen is called AddEditOrderLine.lsml

    I am inserting this code into the OrderLines_ItemTap action on the BrowseOrderLines screen, just as you advised in your article.

    The code reads...

    myapp.BrowseOrderLines.OrderLines_ItemTap_execute = function (screen) {
        // Write code here.
        myapp.showAddEditOrderLine(null, {
            beforeShown: function (addEditOrderLines) {
                addEditOrderLines.BrowseOrderLines = screen.OrderLines.selectedItem;
            },
            afterClosed: function (addEditOrderLine, navigationAction) {
                if (navigationAction === msls.NavigateBackAction.commit) {
                    screen.OrderLines.selectedItem.details.refresh();
                }
            }
        });
    };

    I am sure there is something wrong in there but I cannot figure out what. Right now the when I tap an item on the Browse Screen, the screen will navigate to the Edit screen, but it is broken. It is just  'greyed out', so to speak, and nothing works.

    Thank you!

    Friday, January 08, 2016 8:59 PM
  • You probably just need to make sure you are specifying an entity for the parameter of the AddEditOrderLine screen.  BrowseOrderLines is the name of screen, not the name of the entity parameter, correct?  If so, this line won't work:

    addEditOrderLines.BrowseOrderLines = screen.OrderLines.selectedItem;

    It probably needs to be something like:

    addEditOrderLines.OrderLine = screen.OrderLines.selectedItem;

    Better yet, just pass the parameter instead of null and get rid of the beforeShown function.

    myapp.BrowseOrderLines.OrderLines_ItemTap_execute = function (screen) {
         // Write code here.
         myapp.showAddEditOrderLine(screen.OrderLines.selectedItem, {
             //beforeShown: function (addEditOrderLines) {
                 //addEditOrderLines.BrowseOrderLines = screen.OrderLines.selectedItem;
             //},
             afterClosed: function (addEditOrderLine, navigationAction) {
                 if (navigationAction === msls.NavigateBackAction.commit) {
                     screen.OrderLines.selectedItem.details.refresh();
                 }
             }
         });
     }; 

    Friday, January 08, 2016 9:57 PM
  • Hello! Thank you for assisting with this!!

    This is the code I am using now, after reading your suggestion...

    myapp.BrowseOrderLines.OrderLines_ItemTap_execute = function (screen) {
        // Write code here.
        myapp.showAddEditOrderLine(screen.OrderLines.selectedItem, {
            //beforeShown: function (addEditOrderLines) {
            //addEditOrderLines.OrderLines = screen.OrderLines.selectedItem;
            //},
            afterClosed: function (addEditOrderLine, navigationAction) {
                if (navigationAction === msls.NavigateBackAction.commit) {
                    screen.OrderLines.selectedItem.details.refresh();
                }
            }
        });
    };

    However, I still observe the same behavior. The save action is only saving and then navigating back to the Browse Screen, but not refreshing the Browse Screen.

    Am I coding this in the right place? I am putting the code on the Item Tap action of the OrderLine list on the Browse Screen.

    Should it be put somewhere on the addEdit screen? Or on the Tap action of the save button?

    To me that would make more sense, but I probably do not think like a programmer. I hope I am learning to ;).

    Right now this code seems to say: "When I tap on an item in the OrderLine list on the Browse Screen, show the AddEditOrderLine screen for the selected item. afterClosed the selected item addEdit screen, commit any changes to the database and refresh the screen OrderLines."

    Is that correct? Even if this is all executed from code on the Item Tap action of the list on the Browse Screen, I do not have it working yet with the above code.

    I fixed this. The last line:

    afterClosed: function (addEditOrderLine, navigationAction) { if (navigationAction === msls.NavigateBackAction.commit) { screen.OrderLines.selectedItem.details.refresh();

    I changed screen.OrderLines.selectedItem.details.refresh();

    to: screen.OrderLines.refresh();

    And now it works.

    Thank you!!

    EDIT:

    I had previously proposed this solution as the answer. However, I have found that all this is doing is refreshing the state of the items in the list, not the page itself. I know this because when I search for an item, select it, modify it, then save changes, it will navigate back and refresh the list item itself, but the SEARCH box is still populated, thus there is still a filter on the list. 

    I am now trying to figure out how to refresh the page itself, in order to clear the previous search criteria. After that, I will be working on focusing the curser into the Search box on the page as well.

    Any advice for those tasks much appreciated ;)

    Thank you!

    • Proposed as answer by CreedCor Monday, January 11, 2016 2:43 PM
    • Unproposed as answer by CreedCor Monday, January 11, 2016 5:28 PM
    • Edited by CreedCor Monday, January 11, 2016 5:32 PM
    Monday, January 11, 2016 1:50 PM