4

What it does

I have a simple webpart that pulls in train information to display how many minutes are left and displays the data in the UI. There is a refresh link to refresh the data in the UI. When the results are acquired, it appends the data to either the red line or yellow/green line as shown below.

UI Example

REFRESH LINK
RED LINE TRAINS:
Silver Spring - Minutes: 1
Twinbrook - Minutes: 1
Glenmont - Minutes: 6
Twinbrook - Minutes: 9
Silver Spring - Minutes: 10
Grosvenor-Strathmore - Minutes: 11

YELLOW/GREEN LINE TRAINS:
Greenbelt - Minutes: ARR
Greenbelt - Minutes: 2
Franconia-Springfield - Minutes: 3
Branch Ave - Minutes: 5
Mt Vernon Sq 7th St-Convention Center - Minutes: 6
Branch Ave - Minutes: 10

The problem

This code works fine in the Classic experience webpart. However, in the Modern experience, I've observed that the webpart is being refreshed. This changes the state of the HTML to that of when the app was first added, ignoring the properties in my drop downs. This means an html container will no longer be present to have the data attached to.

Aside from the architectural issues I've been given, is there a way that I can stop the webpart from refreshing? The ajax call should run independently of the webpart.

Code sample

function loadMetro() {
    $(".trainEntry").remove();
    var redLine = $("#wmatared" + token);
    var yellowLine = $("#wmatayel" + token);

    var wmataAPI = "https://api.wmata.com/StationPrediction.svc/json/GetPrediction/B01,F01";
    $.ajax({
        data: "api_key=67te5y756nwun3x584v6hy3k",
        url: wmataAPI,
        success: function(parsed_json) {
            console.log("Results are in"); 
            var k = parsed_json["Trains"].length; 
            $.each(parsed_json["Trains"], function(k, v) {
                var line = v["Line"];
                var car = v["Car"];
                var dest = v["DestinationName"];
                var mins = v["Min"];

                if(line == 'RD') {          
                    redLine.append("<li class='trainEntry' data-id=" + car + ">" + dest + " - Minutes: " + mins + "</li>");
                }
                if(line == 'YL' || line == 'GR') {
                    yellowLine.append("<li class='trainEntry' data-id=" + car + ">" + dest + " - Minutes: " + mins + "</li>");
                }
            });
         },
        error: function() {
            $("#wmata").append("Error receiving data from WMATA web service.");
        }
    });
}

Here is some detail outside of the problem

This code is loaded in client sites via Remote Provisioning. The webpart is a React SPFX webpart that allows the user to select an application. Each application is really a javascript file. This emulates what a content editor/script editor webpart could do, but with better functionality around it.

Here is a link to the gist of 3 pages https://gist.github.com/anonymous/44b70cdcba0d119282bdba40937b0b6b

  • Could you provide some code snippet to show how you are currently updating the page? It would also help to know if you are using any other frameworks. – maleman Jun 19 '17 at 20:55
  • I updated it for you – Brent Jun 19 '17 at 21:41
1

I could be wrong, but it looks like you are storing the data in the DOM itself - that's not a great approach. In general you should update a data store and then trigger a render, where the render pulls from the data store. That way, on a rerender / refresh / etc. the data is present and can be re-rendered.

Does that make sense?

  • We use remote provisioning to deliver javascript based applications. SPFX is a wrapper to render the container dynamically. You're correct, its not the best approach potentially for SPFX. However, I don't know of a better approach for a modern webpart that integrates in with remote provisioning in this manner. For the data store, are you referring to using local storage? My approach from a code perspective is to have the app div written in the render (this.props.name). The applications hook into the div to render their HTML. Is there a method/tutorial I should be looking at for SPFX? – Brent Jun 20 '17 at 19:40
  • Sorry - I didn't quite get my point across. You don't need to persist the data in SharePoint (or in the webpart properties collection - which gets persisted), you simply want to have it stored at runtime in a variable that you can access separate from the DOM. in poor pseudocode - struct trainData {car:string, dest:string, time:datetime} currentData:trainData[] = {{124, Seattle, 12:10},{146, Portland, 14:20},{250,Vancouver,13:10}} void render() clearDiv; foreach(trainData in currentData} { add HTML row; } } – PatMill_MSFT Jun 21 '17 at 0:03
  • (I kind of suck at formatting in comments, sorry). Now when render() is called, it still has the data that was displayed, and you can regenerate the correct DOM. You would want your ajax call to populate the data, then call Render. And apologies, I'm not a react dev, so the example isn't really accurate in that regard, but the general idea is the same. – PatMill_MSFT Jun 21 '17 at 0:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.