Benjamin Jesuiter Benjamin Jesuiter - 1 month ago 6x
Dart Question

Angular2 dart Property binding not updating

Hello Dart and Angular Folks,
following Problem:

I have the following template part in my app_component.html, which is the template of my app_component.dart custom component.

<!-- monitoring active breakpoints-->
<jb-responsive-breakpoints [breakpoints]="breakpoints"

<!-- using list of active breakpoints -->
<jb-menu [activeBreakpoints]="activeBreakpoints">
<!--some menu items, irrelevant for this problem-->

<!-- testing list of active breakpoints-->
Active Breakpoints:
<li *ngFor="let breakpoint of activeBreakpoints;"> {{breakpoint}}</li>

Jb-responsive-breakpoints and jb-menu are custom components too. The ul below tests proper functionality of jb-responsive-breakpoints.

The variables "breakpoints" and "activeBreakpoints" used in this template are defined inside app_component.dart with the following code:

//Mapping from window min-width for this breakpoint to label
Map<int, String> breakpoints = {0:'small', 310:'medium', 450:'large', 600:'xlarge'};

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

What should happen:

  • jb-responsive-breakpoints registers listeners for given widths

  • If current width of the window grows above one breakpoint, the "activeBreakpoints" list will be updated. This list contains all currently active breakpoints, like css allows all matching media queries to be active at once

  • This seems to work as intended because the ul in the template updates accordingly.

The Problem:

jb-menu should get the list of activeBreakpoints to figure out, when to change it's appearance. the activeBreakpoints property on jb-menu is a setter, to be like an event handler.

The activeBreakpoints property on jb-menu is defined like this:

List<String> _activeBreakpoints;

set activeBreakpoints(List<String> breakpoints) {
_log.finest("ActiveBreakpoints list changed");
_log.finest("Active Breakpoints: ${breakpoints.fold("", (prevVal, elem) => "$prevVal, $elem")}");
_activeBreakpoints = breakpoints;

get activeBreakpoints {
return _activeBreakpoints;

- setter is called with empty list - logical because of initialization
- No Setter will be called on further breakpoint change (can prove this with log messages - no "activeBreakpoints changed" log message when resizing the window)
- Confusing: when logging active breakpoints in jb-menu component in
function, all current breakpoints are visible as intended:

ngAfterViewInit() {
currentBreakpoints: $activeBreakpoints

This produces:

currentBreakpoints: [small, medium, large, xlarge]

or fewer breakpoints, depending on window size.

I can imagine, that this is due to the list reference being identical in both components.

But my menu component relies on the setter being called - like an event handler.

Some Ideas how to fix this?

PS: If more code / explanation is required, please ask! :)


Problem solved

So the problem is, that angular 2 doesn't call the setter, if the reference of the binding has not changed.

3 possible Solutions (credits to Günter Zöchbauer):

  1. Change the reference of the binding on every change. I will use this inside my jb-responsive-breakpoints component, since it's the easiest to implement and should not make a huge performance issue with small lists. Can be implemented with eventEmitter.emit(listObject.toList()) instead of eventEmitter.emit(listObject)

  2. Use a Stream to have individual events

    • Create a StreamController outside of the component emitting events (to avoid an output property which only emits one stream event)
    • pass the StreamController to the component emitting events
    • pass the attached stream to the component / all components which are interested in an event from the event-emitting component
    • use that Stream to have individual events
    • Conclusion: I did not use it. It forces the user of your component to implement this stream handling. Could be better for event components producing many events.
    • Consider instead: DoCheck Method below
  3. Implement the DoCheck interface and use IterableDiffers to ajust change detection of angular