2

I have a controller that defines:

  • some properties that control how my ui looks like
  • a method that may be called to change these properties

I also have a directive that receives the controller's method as a parameter to be able to call it.

After angular.dart v0.9.9. any change in the controller's properties is not detected anymore. Since I use scope only implicitly, through the controller's properties, I am not sure if/how I should use 'scope.context', mentioned in the 'breaking changes' section of angular.dart 0.9.9.

How can I fix this?

[update]

Below is some code:

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <title>test</title>
  </head>
  <body ng-cloak ng-controller="app-ctrl">
    <div>selections: {{ ctrl.selections }}</div>
    <div class="test-click" whenclicked="ctrl.goRight()">click</div>
    <script type="application/dart" src="/test/web/main.dart"></script>
    <script src="packages/browser/dart.js"></script>
  </body>
</html>

main.dart

library test;
import 'package:angular/angular.dart';
import '../lib/src/app_ctrl.dart';
import '../lib/src/click_dir.dart';
void main() {
  ngBootstrap(module: new TestModule());
}
class TestModule extends Module {
  TestModule() {
    type(AppCtrl);
    type(TestClickDir);
  }
}

app_ctrl.dart

library app;
import 'package:angular/angular.dart';
/** AppCtrl */
@NgController(selector: '[ng-controller=app-ctrl]', publishAs: 'ctrl')
class AppCtrl {
  List selections;
  AppCtrl() {
    selections = ['a','a'];
  }
  void goRight() {
    selections.add('a');
  }
}

click_dir.dart

library clickable;
import 'package:angular/angular.dart';
import 'dart:html';
/** TestClickDir */
@NgDirective(selector: '.test-click', map: const {
  'whenclicked': '&click'
})
class TestClickDir implements NgAttachAware {
  Function click;
  Element self;
  TestClickDir(Element el) {
    self = el;
  }
  void attach() {
    self.onClick.listen((e) => click());
  }
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
alearg
  • 685
  • 7
  • 17
  • Do you get any error? I don't see any necessity to change anything. – Günter Zöchbauer Mar 17 '14 at 07:51
  • If you try the above example, initially, you see that list 'selections' contains 'aa'. If you then click on 'click', the method 'goRight' is called, an 'a' is added in the 'selections' list, but the view never gets updated, whereas before 0.9.9, it was updating. – alearg Mar 17 '14 at 12:48
  • Just a hint - you can use `ng-click="ctrl.goRight()"` instead of the `whenclicked` attribute. I can reproduce but have no idea of the cause. – Günter Zöchbauer Mar 17 '14 at 13:13

3 Answers3

1

I guess this is due to optimizations because watching collections is expensive. Could also be a bug though.

I suppose you are using this only for debugging purposes? A slightly different result can be achieved easily with:

{{ ctrl.selections | json }} // prints: ["a","a","a","a","a","a","a"]

just found this works better

{{ ctrl.selections.toString() }} // prints: [a, a, a, a, a, a, a]
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
1

I believe this is a bug, because even the watch is not firing, when the length of list changes. If you put a new list into selection (selection = ['a', 'a', 'a']), then the change is updated.

Here is the working example, where selections = selections; makes it work. The _scope.watch is not needed ofcourse, it's here just to give the example of the new syntax (The watch-syntax has changed in version 0.9.9).

EDIT: THIS EXAMPLE IS NOT WORKING. I don't know why it worked when I tested it. I have had to make some mistake earlier, but anyway this is not working. I added the working solution (https://groups.google.com/forum/#!msg/angular-dart/v_t2RUz9lrU/HY7DzAj554sJ)

  AppCtrl(Scope _scope) {
    _scope.watch('selections', (newValue, oldValue) => print("selections: $newValue"), context: this);
    selections = ['a','a'];
  }

  void goRight() {
    selections.add('a');
    selections = selections;
    // or
    selections.add('');
    selections[selections.length-1]='a';
    // following works, the code above don't work
   selections = (selections..add('a')).toList();
  }
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
grohjy
  • 2,059
  • 1
  • 18
  • 19
  • This is intentional. I saw a discussion today in the AngularDart GitHub repository (try to find the post again). For collections only identity changes are watched. For ng-repeat a bit more is watched. – Günter Zöchbauer Mar 17 '14 at 19:50
  • I understand that the changes in the list items are not watched (see: http://stackoverflow.com/a/20962381/2777805), but I think if the nb of items in the list is changed, it should be notified. I edited my answer and added a new working solution (// or ...). This solution is IMO the same as `add('a')` ie. content of the list changes in both cases the same way. – grohjy Mar 17 '14 at 20:14
0

Please have a look here for an explanation of what is going on.

As far as I understand it, a change will never fire because the list doesn't change identity. This code used to work because a re-render, apparently, was always carried out. This is not the case any more for efficiency reasons.

alearg
  • 685
  • 7
  • 17
  • Efficiency is good and now we know how to fire a change if needed (just assign the original value of one item back to itself). I have to check how ng-repeat works now. – grohjy Mar 17 '14 at 20:55
  • ng-repeat works fine, but requires `ng-repeat="selection in ctrl.selections track by $index"` as stated in your link. My earlier solution was not working, I made some mistake somewhere. Now my answer is updated with working solution. – grohjy Mar 18 '14 at 04:15