3
votes

In our Angular-dart application, some components (@NgComponent) are defined. The first time, such a component is shown, it is displayed properly. From the second time on, sometimes the component is shown in the web app, sometimes not. Debugging indicates that, even when not shown, the code of the component is executed. No exceptions/stacktraces seem to occur. When trying to track down the issue, we let the Component implement NgShadowRootAware and we added the method void onShadowRoot(ShadowRoot shadowRoot) {}. Every time a breakpoint is put in the onShadowRoot method, the component is properly shown. When the breakpoint is removed, most of the time the component html is not shown in the web app.

Apparently, resizing (several times) the browser window seems to make the component show up.

view_objectdata_component.dart

library view_objectdata_component;

import 'package:angular/angular.dart';
import 'dart:html';
import '../model/model.dart';


@NgComponent(
    selector: 'view-objectdata',
    cssUrl: '../lib/component/view_objectdata_component.css',
    templateUrl: '../lib/component/view_objectdata_component.html',
    publishAs: 'cmp'
)
class ViewObjectDataComponent implements NgShadowRootAware {

  @NgTwoWay('objectdata-map')
  Map<String, ObjectData> dataMap;  
  @NgTwoWay('readonly')
  bool readonly = true;  

  @NgTwoWay('editLink')
  String theEditLink;  

  String _id;

  ViewObjectDataComponent(RouteProvider routeProvider) {
    _id = routeProvider.parameters['id'];
  }

  bool get hasEditLink => theEditLink != null;
  String get editLink => theEditLink.replaceAll('<id>', _id);

  ObjectData get data  {
    ObjectData val = dataMap[_id];
    return val;
  }

  List<ObjectAttribute> get attributes {
    List<ObjectAttribute> list = [];
    for (ObjectAttribute simAtt in data.attributes.values) {
      list.add(simAtt);
    }
    return list;
  }

  void onShadowRoot(ShadowRoot shadowRoot) {
    shadowRoot.querySelector('#myDiv').children.add(
        new SpanElement()..text = ''
    );
  }
}

view_objectdata_component.html

<div id='myDiv'>
  <h3>{{cmp.data.getAttVal('Name')}}</h3>
    <div><strong>ID: </strong>{{cmp.data.id}}</div>
    <ul>    
      <li ng-repeat="att in cmp.attributes">
         <view-attributevalue objectattribute="att" readonly="cmp.readonly"></view-attributevalue>
      </li>
    </ul>
  <span ng-if="cmp.hasEditLink">    
    <a class="extra-space" href="{{cmp.editLink}}">
      <input type="button" value="Edit">
    </a>
  </span> 
</div>

invoked by:

{{ctrl.changeMainSection('applications')}}
<div>
 <br/>
 <div class="alert alert-info alert-dismissable fade in">         
  <view-objectdata 
    objectdata-map="ctrl.asDataMap(ctrl.applications)" editLink="'#/appComp/<id>/edit'"        
  >   
  </view-objectdata>
  </div>
</div>
1
Very probably a timing issue. Can you post some code? - Günter Zöchbauer
I added some code to the post. If required, I can provide a zip file with the project code that runs with some local demo data. version: Dart Editor version 1.2.0.release (STABLE) / angular 0.9.8 - hbkn
Can you create a GitHub repo with the source. What I do not understand yet is how do you 'show' the component a 'second time'. - Günter Zöchbauer
Code should be available at: github.com/hbkn/lndscp/tree/master/lndscp . => click on an application to show the specific detail (=implemented by a component). BTW: Apparently, resizing (several times) the browser window might make the component show up. - hbkn
I can reproduce the problem. I haven't found the cause yet. - Günter Zöchbauer

1 Answers

1
votes

I think when your data (applications) gets loaded asynchronically from the queryService this update doesn't trigger the entire chain of dependencies. When you have a breakpoint loading data finishes in the meantime and then all is displayed. If you don't have the breakpoint Angular is done rendering and somehow doesn't recognize the data changes.

There are some patterns in your code that Angular doesn't like that may cause this behavior. (If you upgrade to Angular 0.9.9 you will get some exceptions)

There are several methods where you do things like

List<ApplicationComponent> get applications creates a new list every time.
String tabClassForMainSection(String section) Angular seems not to like code like this (not sure if this should work) maybe a Bug in Angular (https://github.com/angular/angular.dart/issues/738).
Map<String, ObjectData> asDataMap(List list) { returns a new collection each time it gets called.

Maybe you should consider a different strategy for loading the data. You could inject the QueryService to the component and make an async getApplications method that you call from the component like queryService.getApplications().then((data) => updateApplications(data));

When you take a look at the debug output I posted here https://github.com/angular/angular.dart/issues/738 you see how often Angular calls methods to check for data updates. It is very inefficient if each time a new collection is created. This is the reason why it is not supported in 0.9.9 anymore.

I hope this helps a bit.