-
Notifications
You must be signed in to change notification settings - Fork 248
No getter for ... error, when working with dynamic expressions and angular transformer #1137
Comments
Would it be possible to see an example of the problem (i.e. some code snippet)? |
This very same problem exists in dart-ng-infinite-scroll, I had filed a similar issue on infinite-scroll. Please read the description on issue for complete explanation. Relevant source code lines are L17 and L62 of ng_infinite_scroll.dart |
Thank you, @adarshaj, but I'm afraid the proposed solution won't work in our case. The thing is that the expression we evaluate is just not known at compilation time, but is retrieved later in an AJAX call. Here is an extremely simplified demonstration code of what we do. When run in Dartium, works well, but when compiled using angular transformer, I receive " No getter for 'categories'." error message. index.html <!DOCTYPE html>
<html ng-app>
<head>
<title>Chapter Six - A Simple Recipe Book</title>
<script type="text/javascript" src="web/packages/web_components/platform.concat.js?"></script>
<script type="text/javascript" src="web/packages/web_components/dart_support.js"></script>
<script type="application/dart" src="recipes.dart"></script>
<script type="text/javascript" src="web/packages/browser/dart.js"></script>
</head>
<body>
<h1>Recipes</h1>
<my-table></my-table>
</body>
</html> recipes.dart import 'package:angular/angular.dart';
import 'package:angular/application_factory.dart';
import 'package:di/di.dart';
import 'dart:html';
import 'dart:convert';
class MyAppModule extends Module {
MyAppModule() {
bind(MyTable);
bind(QueryService);
bind(ViewTemplate);
}
}
@Injectable()
class QueryService {
// get data for the table (normally from a server)
Map getTableData() {
return JSON.decode('''
{
"title" : "Recipe Book",
"categories" : [
{
"name" : "lunch",
"recipes" : [ {
"name" : "lunch 1",
"amount" : 4,
"amountUnits" : "portions",
"rating" : 5,
"preparation" : 10,
"preparationUnits" : "min."
}, {
"name" : "lunch 2",
"amount" : 600,
"amountUnits" : "mL",
"rating" : 3,
"preparation" : 1,
"preparationUnits" : "hour"
}
]
}
]
}''');
}
// get configuration for the table (normally from a server)
Map getTableConfig() {
return JSON.decode('''
{
"rowsExpression" : "categories[0].recipes",
"cols" : [ {
"title" : "name",
"cellFormat" : "{{name}}"
}, {
"title" : "amount",
"cellFormat" : "{{amount}} {{amountUnits}}"
}, {
"title" : "rating",
"cellFormat" : "{{rating}}"
}, {
"title" : "preparation",
"cellFormat" : "{{preparation}} {{preparationUnits}}"
}
]
}''');
}
}
@Component(
selector: 'my-table',
publishAs: 'ctrl',
template: '''<table>
<tr><td ng-repeat="col in ctrl.cols">{{col.title}}</td></tr>
<tr ng-repeat="row in ctrl.rows">
<td ng-repeat="col in ctrl.cols"><view-template template="{{col.cellFormat}}"
data="row"></view-template></td>
</tr>
</table>''')
class MyTable {
QueryService queryService;
Scope scope;
List rows;
List cols;
MyTable(this.queryService, this.scope) {
var cfg = queryService.getTableConfig();
var rowsExpression = cfg['rowsExpression'];
rows = scope.eval(rowsExpression, queryService.getTableData());
cols = cfg['cols'];
}
}
@Component(
selector: 'view-template',
publishAs: 'ctrl',
map: const {
'template' : '@template',
'data': '=>data'
}
)
class ViewTemplate implements ShadowRootAware {
final Injector _injector;
final Scope _scope;
final DirectiveMap _directiveMap;
final ViewCache _viewCache;
bool _viewUpdated = false;
ShadowRoot _shadowRoot;
String _template;
Map _data;
ViewTemplate(this._injector, this._scope, this._directiveMap, this._viewCache);
String get template => _template;
set template(String value) {
_template = value;
_updateView();
}
Map get data => _data;
set data(Map value) {
_data = value;
_updateView();
}
void onShadowRoot(ShadowRoot shadowRoot) {
_shadowRoot = shadowRoot;
_updateView();
}
void _updateView() {
if(_viewUpdated) {
return;
}
if(_template==null || _data==null || _shadowRoot==null) {
return;
}
Scope childScope = _scope.createChild(_data);
Injector childInjector = _injector.createChild([new Module()..bind(Scope, toValue: childScope)]);
ViewFactory viewFactory = _viewCache.fromHtml(_template, _directiveMap);
var view = viewFactory(childInjector);
_shadowRoot.nodes.addAll(view.nodes);
_viewUpdated = true;
}
}
void main() {
applicationFactory()
.addModule(new MyAppModule())
.run();
} |
@michalpie Do you know the expressions ahead of time (and you just bring them later to the client) or you are unable to tell which expressions will be used at runtime ahead of time? |
I am unable to tell ahead of time what expressions will be used and how the data will look like. |
I think you need getters because for now we do not differentiate when you are accessing an object or an array. ie We require getters for accesing object properties. I think this might be solved by #1040 after which you will have to use "[]" to access Map / List. Meanwhile, could you please try to replace your expressions:
|
Thank you, Victor, the solution with map syntax works fine. |
Could you please close the issue if there is no more problem. |
In our application, we often use Scope.eval() to evaluate expressions which are not known at compilation time (they are retrieved from server in AJAX). Likewise, we often generate HTML templates in memory, based on AJAX data, which contain expressions not known at compilation time. In all these cases after compilation using angular transformer, we get "No getter for ..." error message.
@MirrorsUsed and override: '*' stopped working, so we now have completely no way to minify the javascript code.
AngularDart: 0.12.0
Dart 1.4.2
The text was updated successfully, but these errors were encountered: