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

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.

Related

Angular dart component init

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.

BreezeJS editing data not working

I was able to follow the instruction on adding data, that part was easy and understandable. But when I tried to follow instructions for editing data, I'm completely lost.
I am following the todo sample, which works quite well, but when I tried to add to my own project using the same principle, nothing works.
in my controller, I have the following:
function listenForPropertyChanged() {
// Listen for property change of ANY entity so we can (optionally) save
var token = dataservice.addPropertyChangeHandler(propertyChanged);
// Arrange to remove the handler when the controller is destroyed
// which won't happen in this app but would in a multi-page app
$scope.$on("$destroy", function () {
dataservice.removePropertyChangeHandler(token);
});
function propertyChanged(changeArgs) {
// propertyChanged triggers save attempt UNLESS the property is the 'Id'
// because THEN the change is actually the post-save Id-fixup
// rather than user data entry so there is actually nothing to save.
if (changeArgs.args.propertyName !== 'Id') { save(); }
}
}
The problem is that any time I change a control on the view, the propertyChanged callback function never gets called.
Here's the code from the service:
function addPropertyChangeHandler(handler) {
// Actually adds any 'entityChanged' event handler
// call handler when an entity property of any entity changes
return manager.entityChanged.subscribe(function (changeArgs) {
var action = changeArgs.entityAction;
if (action === breeze.EntityAction.PropertyChange) {
handler(changeArgs);
}
});
}
If I put a break point on the line:
var action = changeArgs.entityAction;
In my project, it never reaches there; in the todo sample, it does! It completely skips the whole thing and just loads the view afterwards. So none of my callback functions work at all; so really, nothing is subscribed.
Because of this, when I try to save changes, the manager.hasChanges() is always false and nothing happens in the database.
I've been trying for at least 3 days getting this to work, and I'm completely dumbfounded by how complicated this whole issue has been for me.
Note: I'm using JohnPapa's HotTowel template. I tried to follow the Todo editing functionality to a Tee.. and nothing is working the way I'd like it to.
Help would be appreciated.
The whole time I thought the problem was in the javascript client side end of things. Turned out that editing doesn't work when you created projected DTOs.
So in my server side, I created a query:
public IQueryable<PersonDTO> getPerson(){
return (from _person in ContextProvider.Context.Queries
select new PersonDTO
{
Id = _person.Id,
FirstName = _person.FirstName,
LastName = _person.LastName
}).AsQueryable();
}
Which just projected a DTO to send off to the client. This did work with my app in fetching data and populating things. So this is NOT wrong. Using this, I was able to add items and fetch items, but there's no information that allowed the entitymanager to know about the item. When I created an item, the entitymanager has a "createEntity" which allowed me to tell the entitymanager which item to use.. in my case:
manager.createEntity(person, initializeValues);
Maybe if there was a "manager.getEntity" maybe that would help?
Anyways, I changed the above query to get it straight from the source:
public IQueryable<Person> getPeople(){
return ContextProvider.Context.People;
}
Note ContextProvider is:
readonly EFContextProvider<PeopleEntities> ContextProvider =
new EFContextProvider<PeopleEntities>();
So the subscribe method in the javascript checks out the info that's retrieved straight from the contextual object.. interesting. Just wish I didn't spend 4 days on this.

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
}

Is there an ng-directive or a default function, which can be used as a scope.watch-function

I have a component, that has an #NgOneWay binded attribute message. I have {{cmp.message}} within my html template and it will update automatically when attribute changes. If I want to run a myFunc-function, when cmp.message changes, I can use _scope.watch('message', (newValue, oldValue) => myFunc(), context: this); in my constructor.
Is there a default function, which will fire when my message-attribute changes, like onMessage()?
Or ng-directive, which could be used instead of watch, like ng-onmessage="cmp.myFunc()"?
I think the easiest (and IMHO most beautiful) solution is to implement your cmp.message as getter/setter and execute your function in the setter.
This way you don't need a watch at all.
var _message;
#NgOneWay
get message => _message;
set message(val) {
_message = val;
myFunc();
}

Breeze Durandal Access shell viewmodel variable from view

I have a pretty simple thing I want to accomplish but I cannot figure out how or if it is even possible. I am using the Hot Towel template to start with. In the shell viewmodel I have a user observable. I would like to be able to reference that user observable from other pages on my site. For example from the home page. I tried a couple of things but it doenst appear as though I can access the shell from the composed view. I have a working solution at the moment that uses event pub/sub calls from the shell to pass the user data to anyone listening whenever the data changes (home view in this example). This works it just seems a little clunky and not really the ideal way to handle this. This user observable will need to be used all throughout the site to determine when certain features should be available and to show a particular users projects.
Is there a way to data bind to a knockout observable contained in the shell viewmodel from the home view?
You might consider having a global.js that returns a singleton, which you include in view models as needed.
define(function () {
return {
sharedObservable: ko.observable(),
sharedObservableArray: ko.observableArray(),
...
};
});
Using global in a viewmodel.
define([..., global], function (..., global) {
...
global.sharedObservable('updated');
// As an alternative use a local var for easier access
// var localVar = global.sharedObservable;
// localVar('updated')
...
});
The easiest way is to import the shell module into your viewmodel with requirejs and then expose the shell viewmodel as a variable on the module's viewmodel.
Somehting like this:
// Some viewmodel
define(['shell'], function(shell){
var vm = {
shell: shell,
...
};
return vm;
});
Then in your view, you can bind using $root.shell
<span data-bind="text: $root.shell.shellObservable"></span>
Non of previous answers worked for me. Thus, I tried another variant of access to shell and it made the job done.
I've got this in my shell.js:
define(['plugins/router', 'durandal/app'], function (router, app) {
return {
// I need an access to this array in my view
breadcrumbs: ko.observableArray([]),
...
};
});
And this in my view:
define(function () {
var ctor = function () {
this.pageTitle = 'Preview';
this.activate = function () {
require('viewmodels/shell').breadcrumbs([...]);
};
};
return ctor;
});
So, require('viewmodels/shell') actually returns reference to a shell object.

Resources