Why doesn't the model get updated? - dart

I'm going through the angular dart tutorials and I tried to make a list of items and when one is clicked fill an input with the clicked item's text. This works OK until I modify the text in the input. After that clicking another item in the list does not update the text in the input field (before it did), and neither gets the item in the list modified.
My starting point the 2 tutorial, but trying to combine it with some input as in the first one.
My html file:
<!DOCTYPE html>
<html ng-app>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test</title>
</head>
<body>
<div data-list>
<ul>
<li ng-repeat="data in ctrl.dataList" ng-click="ctrl.selectData(data)">{{data.text}}</li>
</ul>
<input type="text" value="{{ctrl.selected.text}}">
</div>
<script type="application/dart" src="spa.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>
My dart file:
import 'package:angular/angular.dart';
#NgController(
selector: '[data-list]',
publishAs: 'ctrl'
)
class DataController{
DataValue selected;
List<DataValue> dataList = [new DataValue("uno"), new DataValue("dos"), new DataValue("tres")];
void selectData(DataValue selected){
this.selected = selected;
}
}
class DataValue{
#NgTwoWay('text')//Also tried without this. Same result
String text;
DataValue(this.text);
}
class DataAppModule extends Module{
DataAppModule(){
type(DataController);
}
}
void main(){
ngBootstrap(module: new DataAppModule());
}
Any idea what I'm doing wrong?
The desired behavior should be:
the items in the list are displayed
when any of them is click the input field gets updated
when editing the input field's value the currently selected item of the list gets updated with the new text
At any moment clicking an item updates the value of the input file

Use the input element with the ng-model directive to have a two-way binding:
...
<input type="text" ng-model="ctrl.selected.text">
...
The #NgTwoWay annotation is only used in components or controllers, used in class DataValue it is ignored.

Related

Bind a value from a polymer element to the parent page

I have made a simple ploymer element, i need to change an input value on the page that contains that polymer element.
<html>
<head>
<script src="../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="dial-buttons/dial-buttons.html">
</head>
<body>
<input type="text" name="dial-number" id="num-input" />
<paper-material elevation="1">
<dial-buttons></dial-buttons>
</paper-material>
</body>
</html>
And here is the element code:
<dom-module id="dial-buttons">
<template>
<div on-click="handleClick" data-args="0, num-input">
<p>0</p>
<span>+</span>
<paper-ripple></paper-ripple>
</div>
</template>
<script>
Polymer({
is: 'dial-buttons',
handleClick: function(e) {
var args = Polymer.dom(e).path[1].getAttribute('data-args').split(',');
document.getElementById(args[1]).value = args[0]; //Here is the issue!
}
});
</script>
</dom-module>
What im trying to achieve here is, when a click event on the "dial-buttons" element is fierd, the input value on the parent page should get the value sent from this child element.
Checked that part in the documentation.
You create a property which is called let's say myVar, you set notify to true (just like the first example). Inside your function set this.myVar to the value you want and it should be reflected to your attribute which you bind to in your parent element.

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
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.

Custom Element - null reference from query() in constructor

I'm working on my first Dart app, having completed the Game of Darts tutorials. I am trying to create a semantically named top-menu element that will eventually display a list of navigation menu tabs at the top of my page. My Dart app is able to recognize my custom element and calls the associated constructor.
However, I am getting a null reference when trying to query for the UL element within my custom element. I need the UL reference in order to dynamically load my LI elements into the menu.
Question 1:
Should the element be visible in the DOM at the point where the constructor is running?
Question 2:
If it is not yet visible, is there a Dart event I can use to trigger loading of the LI elements after the custom element has been completely loaded into the DOM?
Thanks in advance! For reference, here is the source of my custom element:
topmenu-element.html
<!DOCTYPE html>
<html>
<body>
<element name="top-menu" constructor="TopMenu" extends="div">
<template>
<div>
Top Menu
<ul id="top-menu-list"></ul>
</div>
</template>
<script type="application/dart" src="topmenu-element.dart"></script>
</element>
</body>
</html>
topmenu-element.dart
import 'package:web_ui/web_ui.dart';
import 'dart:html';
class TopMenu extends WebComponent {
List menuItems = ['Session', 'Authentication Services', 'Vehicle Services', 'Subscriber Services', 'Data Services'];
void populateMenu() {
UListElement menuList = query('#top-menu-list');
LIElement newMenuItem = new LIElement();
newMenuItem.text = menuItems[0];
menuList.children.add(newMenuItem);
}
TopMenu() {
// populateMenu();
}
}
I can't speak specifically about the DOM visibility in a constructor with the query method as I'm truthfully not certain. However there are perhaps better methods which you can use, which are called at various stages in the elements lifecycle.
That said, can I ask why you need to use this particular method to add the children. It is probably much easier to do it with the template repeat like so:
<!DOCTYPE html>
<html>
<body>
<element name="top-menu" constructor="TopMenu" extends="div">
<template>
<div>
Top Menu
<ul id="top-menu-list">
<li template repeat="item in menuItems">{{item}}</li>
</ul>
</div>
</template>
<script type="application/dart" src="topmenu-element.dart"></script>
</element>
</body>
</html>
Then there's no need to put any of your menu display code in your constructor.

How do I structure a "Controller" in Dart's web_ui?

I have the following code
xviewcontainer.html
<!DOCTYPE html>
<html>
<head>
<title>xviewcontainer</title>
<link rel="components" href="xsearch.html">
<link rel="components" href="xcard.html">
</head>
<body>
<element name="x-view-container" constructor="ViewContainerComponent" extends="div">
<template>
<template instantiate="if view == 'SEARCH_VIEW'">
<x-search></x-search>
</template>
<template instantiate="if view == 'CARD_VIEW'">
<x-card></x-card>
</template>
</template>
</element>
<script type="application/dart" src="xviewcontainer.dart"></script>
<!-- for this next line to work, your pubspec.yaml file must have a dependency on 'browser' -->
<script src="packages/browser/dart.js"></script>
</body>
</html>
xviewcontainer.dart
import 'package:web_ui/web_ui.dart';
class ViewContainerComponent extends WebComponent {
String view = 'SEARCH_VIEW';
}
I have the event handling code within some other currently rendered sub-component of x-search. How do I get a reference to the containing x-view-container instance? I wish to change the .view property so that x-view-container will render x-card instead of the currently rendered x-search. I would be specifically interested in how to do so from my event handlers relative position, how to do it in a absolute fashion, as well as how to do so in any other manner.
void openCardView(){
WHAT_DO_I_PUT_HERE.view = 'CARD_VIEW';
}
You can query for the element you have on the DOM with query() method. Simplest example is query('x-view-container'). Or assign a class or an id on it and query against that. Then access the xtag property to get the actual web component instance.
Here's an example:
import 'package:web_ui/watcher.dart' as watchers;
main() {
// I'm assuming that the HTML tag is somewhere on the page.
query('x-view-container').xtag.view = 'CARD_VIEW';
watchers.dispatch(); // You may need to call this, or use #observable stuff.
}

why is css not being applied to this jquery anchor button?

I must be missing something very basic in the CSS. My jQuery anchor button is functional, but it's rendering as a simple underlined label, not asa rounded-corner UI button. I would be grateful if someone could point out the error in this simple example.
Thanks
!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<HTML LANG="en-US">
<HEAD>
<TITLE>button test</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Expires" content="Sat, 22 May 2010 00:00:11 GMT">
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.min.js"></script>
<SCRIPT type="text/javascript">
$(document).ready(
function() {
$('a','.test').click(function(){showIntro();return false;});
});
function showIntro()
{
document.location.href="intro.htm";
}
</script>
<body>
<div class='test'>Button</div>
</body>
</html>
You need to actually make it a button using .button(), like this:
$(function() {
$(".test a").button();
});
You can see the jQuery UI demos here and a demo of your markup working here.
You need to add the proper class to the link, using jQuery or otherwise.
Try:
Button
You do not need to make it a button you just need
$(".test a").click(function(){showIntro();return false;});
What you are trying to do with your selector passing the second paramater is the Scope.
The second paramater is not mean to be a string (selector) it should be a jQuery Object.
So if you wanted to do it your way your would have to say
var test = $('.test');
$('a',test).click...
But the 1st method is prefered over doing it this way.
Sorry to be providing an answer, if not "the" answer, to my own question, but I have discovered a clue as to what's going on, if not the ultimate cause of the behavior. Below is code cut and pasted from the Button example on the jQuery website; take it to jsFiddle and run it: it works. But if you remove this line relating to the input-button:
$("button, input:submit, a", ".demo").button();
then the anchor-button fails to render properly. Why is the anchor-element's rendering dependent on the existence of the input-button?
<script type="text/javascript">
$(function() {
$("button, input:submit, a", ".demo").button();
$("a", ".demo").click(function() { return false; });
});
</script>
<style>
</style>
<div class="demo">
<button>A button element</button>
<input type="submit" value="A submit button">
An anchor
</div><!-- End demo -->
​

Resources