Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    #16
    (3.1d, SNAPSHOT_v8.3d_2012-06-12/Pro Deployment 2012-06-12)

    I'm trying to use your suggestion from July 12th here:
    Right now, facets cannot be changed on the fly, however, given a new dataset you can just run the same code to [produce] new instance of FacetChart and destroy() the old.
    I'm using the TimeSeriesChart code I posted a few days ago. I've change the constructor there so that it always assures a unique "ID" is set:
    Code:
    's_chartID' is a static int:
    setID("timeSeriesChart"+(++s_chartID));
    But I'm still getting this when I try to replace my existing chart:

    Code:
    (BaseWidget.java:600) 2012-07-16 18:26:11,276 [ERROR] Uncaught exception
    java.lang.IllegalStateException: Cannot change configuration property 'facets' to [Lcom.smartgwt.client.widgets.cube.Facet;@510d3297 after the component has been created.
        at com.smartgwt.client.widgets.BaseWidget.error(BaseWidget.java:600)
        at com.smartgwt.client.widgets.BaseWidget.error(BaseWidget.java:588)
        at com.smartgwt.client.widgets.BaseWidget.setAttribute(BaseWidget.java:683)
        at com.smartgwt.client.widgets.chart.FacetChart.setFacets(FacetChart.java:1871)
    In my panel's code, I have this layout going on, to create a placeholder within a master VLayout instance:
    Code:
    // 'd_mainContent' is a VLayout...
    d_mainContent.addMember(d_toolbar);
    d_chartPlaceholder = new VLayout();
    d_chartPlaceholder.setWidth100();
    d_chartPlaceholder.setHeight100();
    d_chartPlaceholder.addMember(createTemporaryChart());
    d_mainContent.addMember(d_chartPlaceholder);
    d_mainContent.addMember(d_footer);
    createTemporaryChart() assigns a FacetChart to the iVar 'd_chart'. Then when I have a new dataset and want to render it, I do this:

    Code:
    private void replaceChart(Record[] data)
    {
       if (d_chart != null){
          d_chartPlaceholder.removeMember(d_chart);
          d_chart.destroy();
       }
       d_chart = new TimeSeriesChart<Date,XYPoint>();
    
       ...
    
       // WHEN I TRY TO REPLACE THE CHART, THIS LINE CAUSES THE EXCEPTION (called from within the TimeSeriesChart class):
       setFacets(xAxisFacet, new Facet("description", "thing"));
    
       d_chartPlaceholder.addMember(d_chart);
    }
    Did I misunderstand your guidance earlier? I've successfully used this kind of "placeholder" technique to redraw/repopulate ListGrids with dynamic (client-side-only) field definitions. Will it not work with FacetChart?

    At first I thought that each FacetChart instance having the same 'ID' was the problem, but ensuring they would all be different did not help things.

    1. Can you please advise about the above?

    2. SMALL CODE ENHANCEMENT REQUEST THAT WOULD BE HUGELY HELPFUL HERE: In the error text of the Exception that is generated in this circumstance, could the string "... the component ..." be enhanced with some more descriptive information (the component's ID?) about what the framework thinks has already been created? Clearly in my code above, 'the component' above is a brand new instance of FacetChart that has not yet been rendered.

    Thanks.

    Comment


      #17
      There's no reason to call setID() at all if you are just generating random IDs. Just omit this call.

      A number of calls can force the component to become initialized such that you can no longer call methods that are only allowed pre-initialization. The most common would be adding it to a Layout, which is also a bad general practice: first provide the component's full configuration, then add it to a layout. Otherwise adding it to a layout may cause it to run through sizing and drawing routines who results would be useless after facets have changed.

      If this is part of a general "placeholder" strategy you've used elsewhere, you should revisit it. It could make sense to put a simple visible placeholder such as a Label that says "loading" in a place where a FacetChart or other component will ultimately be if this allows the user to see the screen sooner while a slow data loading process takes place.

      However it doesn't really make much sense to actually use something like a FacetChart or ListGrid as a placeholder if the replacement is just going to be the same type of component configured differently - this just wastes execution time.

      Comment


        #18
        I follow what you're saying in general, but when you say "can force the component to be initialized", which component do you mean, the FacetChart or the VLayout into which it is placed?

        It's not obvious to me, because all of the code above works fine the first time through. The SECOND time through, the Layout object is indeed the same instance but the FacetChart is not, and yet it is the call to the FacetChart that generates the exception. (Or is it (?), hence my second question above, which you didn't answer.)

        Imagine a historical stock market data application with a single Canvas containing dozens of ui components, including querying facilities via a DynamicForm to get historical prices. The user enters a stock symbol and a date range... they click a button to execute a query and a FacetChart elsewhere on the screen (in some screen real estate reserved for that purpose) would display the resulting data as a time series chart. It seems reasonable to want to get just the chart to redraw itself with the new data that the user has just requested.

        If this is part of a general "placeholder" strategy you've used elsewhere, you should revisit it.
        As far as a placeholder strategy, can you please suggest a "best practice" for refreshing the content of a FacetChart which itself is just one widget on a much larger screen?

        Even if I use a Label, as you mention, somehow I have to replace that Label with my FacetChart, and that Label will almost certainly be part of a Layout instance. In my earlier post, I demonstrated my replacement/refresh strategy in the code.
        Code:
        // 'd_chart' is the old instance
        d_chartPlaceholder.removeMember(d_chart);
        ....
        // 'd_chart' is now a new instance
        d_chartPlaceholder.addMember(d_chart);
        If in fact it is the use of Layout that is the underlying cause of the problem, am I not hosed? The use of Layouts in a complicated screen like this is unavoidable.

        I'm all for not "[wasting] execution time", but foremost I'm for getting this to work. Perhaps you can more precisely suggest a best practice that will do both?

        For the record, I'm doing this type of refresh thing with ListGrids containing dynamic column definitions and the performance, to your company's credit, is great and the users love the app. There's no "slow data loading process" and the replacement of the ListGrid works beautifully. I'm just trying to add a chart to the app...

        Comment


          #19
          Well yes, the error message is about a call to setFacets, Layouts do not have facets at all so clearly it cannot be about a call to Layout.

          The placeholder strategy discussed again is for showing something to the end user while a slow data load takes place. In this case you are showing new data for a component that is already visible (hence no need for a placeholder) using data that you've already loaded, it does not apply.

          Once again, for this specific problem, just call setFacets(), setData() and any other methods that provide configuration to the FacetChart *before* adding it to any parent, calling draw() on it, or otherwise forcing it to render.

          We can't give more specific advice because in the only relevant code snippet you've shared, you've got "..." in place of the lines of code that have the problem.

          Comment


            #20
            [TAIL-BETWEEN-LEGS-MODE]
            Mea culpa... The code I posted to you
            Code:
            setFacets(xAxisFacet, new Facet("description", "thing"));
            d_chartPlaceholder.addMember(d_chart);
            was a transposition of what was actually executing on my system. In trying to produce a concise example for you, I took those two lines from two different classes, but indeed, they were executing in this order:
            Code:
            d_chartPlaceholder.addMember(d_chart);
            setFacets(xAxisFacet, new Facet("description", "thing"));
            ...which definitely would be a case of the facets being changed after the new chart instance has been placed into a Layout.
            [/TAIL-BETWEEN-LEGS-MODE]

            Sorry!

            To clear up any remaining confusion in the discussion, there IS the need for a placeholder, as my use case falls into the situation you mentioned on July 12th (and which triggered this entire coding exercise):
            Right now, facets cannot be changed on the fly, however, given a new dataset you can just run the same code to product a new instance of FacetChart and destroy() the old.
            That is indeed what I'm doing now, and it works great. Thanks for hanging in there.

            Comment

            Working...
            X