Draško Kokić
Draško Kokić

Reputation: 1290

Is there a way in angular-dart to explicitly notify a view of a modified model?

I have an app using @NgController and the working use case where an UI action triggers a change in the model, which immediately get reflected in the view. The model consists of a list of objects.

What is not working is when the triggered action is starting some asynchron process which eventually modifies the model (adds new elements in the list). The view gets no update.

I guess this works as designed and I am missing something. What pattern should I use in this case?


UPDATE: Here the minimal code snippet showing the problem:

<html ng-app>
  <head>
    <meta charset="utf-8">
    <title>Angular bug test</title>
    <link rel="stylesheet" href="angular_bug_test.css">
    <script src="http://lounge-server.jit.su/socket.io/socket.io.js"></script>
  </head>
  <body test>
    <h1>Angular bug test</h1>

    <p>The number of element in the list is {{controller.list.length}}</p>
    <input ng-click="controller.addElementSync()" type="button" value="Add Sync"></input>
    <input ng-click="controller.addElementAsync()" type="button" value="Add Async"></input>
    <input ng-click="controller.addElementJsAsync()" type="button" value="Add JS Async"></input>
    <ul>
      <li ng-repeat="element in controller.list">{{element}}</li>
    </ul>

    <script type="application/dart" src="angular_bug_test.dart"></script>
    <script src="packages/browser/dart.js"></script>
  </body>
</html>

and the corresponding dart code:

@NgController(selector: '[test]', publishAs: 'controller')
class TestController {

  List<String> list = new List<String>();

  void addElementSync() {
    list.add("${list.length}. element");
  }

  void addElementAsync() {
    new Timer(new Duration(seconds: 1), () => list.add("${list.length}. element"));
  }

  void addElementJsAsync() {
    context['io']
      .callMethod('connect', ['http://lounge-server.jit.su:80/'])
      .callMethod('on', ['connect', _onConnect]);
  }

  void _onConnect() {
    Logger.root.fine('connected');
    list.add("${list.length}. connected");
    Logger.root.fine('list.length = ${list.length}');
  }

}

When triggering the Add JS Async button the console shows the following:

FINE : connected
FINE : list.length = 6

Unfortunately, neither the ng-repeat nor the {{controller.list.length}} gets updated.


UPDATE: The following workaround fix this problem in JS interop (kudos to James)


  NgZone _zone;

  TestController(NgZone this._zone);


  void addElementJsAsync2() {
    context['io']
      .callMethod('connect', ['http://lounge-server.jit.su:80/'])
      .callMethod('on', ['connect', _zone.run(_onConnect)]);
  }

UPDATE: The bug is still present in 0.11.0 and NgZone has been renamed VmTurnZone

Upvotes: 1

Views: 466

Answers (1)

James deBoer
James deBoer

Reputation: 2495

What you are describing should work out-of-the-box. The only tricky part is dealing with lists: in order to detect changes in the list, and custom directives must use Scope.$watchCollection to watch the collection. Normal watches and attribute maps will miss changes in the list.

Built-in directives which deal with lists (e.g. ng-repeat) already use $watchCollection.

Upvotes: 1

Related Questions