Angular dart component init - dart

Is there a way to wait for the component to be initialized?
#Component(
selector: "my-component",
templateUrl: 'component/my.html',
useShadowDom: false,
publishAs: "ctrl"
)
class MyComponent {
#NgAttr('foo')
String foo;
}
#NgAttr('bar')
String bar;
}
MyComponent(){
print(foo);
print(bar);
}
}
Usage:
<my-component foo="bar" bar="baz"></my-component>
When i use the component like this, the constructor prints: null, null
I could write a setter for foo and bar and check on every set if they are both set. But if no value is provided.. my init is never fired.
Do i have to implement a interface which provides a init method or something?

It's the same as shown here Connecting 2 controllers and have access to the first controllers propertie in the second controller
Implement the AttachAware interface. The values of the instance can't be set before the element is constructed therefore there is no chance to have the fields set from the outside when the constructor is executed.

As Günter said implement either AttacheAware or!! ShadowRootAware. onShadowRoot comes after onAttachAware. The Param it gives you (ShadowRoot) is your custom element. The name is misleading - it also works if useShadowDom is false.

Related

dependency injection for interfaces

I have a component which contains a generic popup, it implements therefore the interface PopupParent
#Injectable()
#Component(
//...
)
class SubjectListComponent implements OnInit, PopupParent {
}
The generic class InfoPopup needs to deal abstractly with its parent (that implements PopupParent), so I would like to take get the parent injected by its interface (instead of being injected by its concrete class SubjectListComponent)
class InfoPopup {
final PopupParent _parent;
InfoPopup(this._parent);
//...non relevant code
}
The issue is that the SubjectListComponent was registred by class in the injector, so the injector won't find what to inject into the InfoPopup class.
If I try to declare my SubjectListComponent manually, I found that it has to be done in the providers constants. but I still don't have my instance of SubjectListComponent when I declare my component...
How could I do that?
I also tried to pass the parent to an #Input:
#Component(
selector: 'info-popup',
templateUrl: 'info_popup.html',
styleUrls: const ['info_popup.css'],
)
class InfoPopup {
#Input()
final PopupParent parent;
InfoPopup(this._parent);
//...non relevant code
}
But then I got stuck on how to inject the this instance from the component client :
subject_list_comp.html:
<div>
<info-popup [parent]="this"></info-popup>
</div>
since dart angular doesn't recognize this as a keyword, but it searches for a property called this in SubjectListComponent.dart
Two issues were created for this question:
https://github.com/dart-lang/site-webdev/issues/514
https://github.com/dart-lang/site-webdev/issues/515
This can be accomplished by providing aliases. multi: true allows to add more than one alias. There is no way to make automatically derive the interfaces.
#Component(
providers: [
const Provider(PopupParent, useExisting: SubjectListComponent, multi: true),
const Provider(PopupParent, useExisting: FooComponent, multi: true)
]
)
class InfoPoupup ...
update
To make
[parent]="this"
work, you could add a getter to the component
get self => this;
and then use
[parent]="self"

extjs 5 : make a data binding for component's custom property

i have a component that extended from the filefield,
and i added a custom property 'serverPath' to it ,and also i have defined the getter and setter .
code :
Ext.define('MyApp.ux.Field.File',{
extend:'Ext.form.field.File',
xtype:'myfilefield',
serverPath:'',
getServerPath:function(){
return this.serverPath;
},
setServerPath:function(serverPath){
this.serverPath = serverPath;
}
});
Ext.create('MyApp.ux.Field.File',{
bind:{
serverPath:'{serverPath}'
},
viewModel:{
type:'myViewModel'
}
});
i will not paste the myViewModel's definition . it is simple.
and it turned out that the binding does not take effect.
can anyone help ?
Your class should be:
Ext.define('MyApp.ux.Field.File',{
extend:'Ext.form.field.File',
xtype:'myfilefield',
config: {
serverPath:''
}
});
And you should be all set because ExtJS will create the setter and getter for you as well as the setter.
In your view model make sure you have a:
data: {
serverPath : 'yourPathGoesHere'
}
Edited
There are two things that were missing:
When a value on the ViewModel changes the changes are asynchronously published by the scheduler. If you want the changes reflected immidiatly you need to use notify on the ViewModel or deffer the logic after the change a bit.
To get custom config properties of a class to notify back the ViewModel of changes you need to add them in the 'publishes' config property.
Please see this updated fiddle.

Wait for dom ready without useShadowDom

I want to wait until my component is fully loaded. The current approach would be to implement the ShadowRootAware interface. However this does not work, if the component disables the use of shadow dom:
#Component(
selector: 'travel-step',
templateUrl: 'packages/TravelPlanner/travelstep/travel_step_component.html',
useShadowDom: false,
publishAs: 'cmp')
class TravelStepComponent extends AttachAware{
I need to disable the usage of ShadowDom, because I want to use styles from my parent object (e.g. Bootstrap). Is there another way to wait for the dom to be ready?
I want to reference a file upload input. At the moment (angular v.012) there seems to be no other way to upload a file.
You can implement ShadowRootAware interface. For example:
class NgFreeTree implements ShadowRootAware {
void onShadowRoot(ShadowRoot shadowRoot) { ... }
}
It should work regardless of useShadowDom attribute.
It does not give you the error message if you use the following signature:
void onShadowRoot(Node n) {
HtmlElement element = n;
...
}

Do something after attribute value got assigned

I would like to do some mapping after the members have been set by angular dart:
#Component(
selector: 'travel-step',
templateUrl: 'packages/TravelPlanner/travelstep/travel_step_component.html',
useShadowDom: false,
publishAs: 'cmp')
class TravelStepComponent {
// Deprecated but impossible to replace, since the new syntax is not ready
#NgTwoWay('step')
TravelStep step;
TravelStepComponent() {
// step is null at the moment
}
}
I'm using angular v. 0.12. When the constructor is called, step is still null.
I could do it with a watch expression but I only want to do it once, so this workaround is not how I want to do it.
You can implement AttachAware and put your code into the attach() method.
Similar behavior can be achieved by implementing ShadowRootAware and onShadowRoot().
You need to give Angular some time to evaluate the bindings and assign the values. Use one of these methods according to your requirements.
Sometimes it might help to (additionally) wrap your code into a
new Future(() {
your code here
});
to delay the execution of your code.
Another approach is to implement a setter and execute your logic there
#NgTwoWay('step')
TravelStep _step;
TravelStep get step => _step;
set step(TravelStep s) {
// your code here
_step = s;
// or here
}

Provide callback for custom component

I made a custom component which basically wraps a d3 line chart. Now I want to be able to register a callback for clicks on the lines in the chart.
I gave the component a #NgCallback parameter, which I then send events to:
class NetworkSummaryComponent implements NgShadowRootAware {
#NgCallback('callback')
Function callback;
void onShadowRoot(ShadowRoot shadowRoot) {
...
chart.callMethod('listen', ['line-click', (ev) {
var name = ev.callMethod('getLineName');
print(name);
callback({'name': name});
}]);
}
}
When using the component, I specify a function of my controller as callback:
<network-summary
...
callback="ctrl.lineClicked">
</network-summary>
However, that function is never actually called, put I know the callback arrives from the JS side because the print in the first snippet is executed.
If I instead specify the attribute as callback="ctrl.lineClicked()" I get a strange exception:
Closure call with mismatched arguments: function 'call'
I could not find any official documentation on how to properly do callbacks, so I'm not exactly sure what I'm doing wrong.. Any ideas?
It turns out that I had to explicitly name the expected arguments in the attributes:
<network-summary
...
callback="ctrl.lineClicked(name)">
</network-summary>
Hope this is useful to the next person having this problem.

Resources