问题
I have an AngularJS application where I want to edit a Date object that is being exposed by ASP Web API through BreezeJS. When I try to edit this field in a HTML form it doesn't quite work. It seems to edit part of the object, or doesn't bind to the date input type at all.
I am wondering what the best way would be to edit Date fields in HTML forms with BreezeJS. I can't find any resources about how one would solve this problem in a proper way.
My own guesses would be:
- Extend the Breeze entity with an extra field that is based on the original date with a getter/setter.
- Not using a date field in the WebAPI, but that doesn't feel right.
Code
In my Angular controller I'm getting the object from Breeze through a repository pattern:
datacontext.session.getById(id)
.then(function (data) {
return vm.session = data;
});
After that the vm.session is filled with the Breeze object, like this:
[{
"$id":"1",
"$type":"TestApp.Model.Session, TestApp.Model",
"Id":3,
"Name":"Second session",
"StartDate":"2014-10-12T00:00:00.000",
}]
Now in my HTML form I'm binding like this:
<input type="date" ng-model="vm.session.startDate" placeholder="Start Date">
It's currenyly showing this date as "Sun Oct 12 2014 02:00:00 GMT+0200 (Romance Daylight Time)" if I use a type "text" instead of "date" in the input field.
And the casing of the ng-model field is correct since I'm using this to create camelCase fields:
breeze.NamingConvention.camelCase.setAsDefault();
So this is fairly straightforward... I'll try to make a JSFiddle or Plunker asap
回答1:
Breeze maintains date properties as JavaScript Date
objects when that's what you say they are in your metadata.
Breeze does not have its own
Date
type.
The HTML5 <input type="date" .../>
date picker is not widely supported yet (see here) so I'm assuming you're relying on the Angular directive to help you.
That directive is designed to bind to a string, not a date object. This probably explains why the wheels are coming off.
I am sorely tempted to argue that the Ng directive should be smarter than this. It should do what it takes to bind to a
Date
object as well as a date string. I just might file that as a bug.
As you discovered, the HTML input tag "just works" if the type is "text". Obviously the date display and data entry are not what you want.
I think the ideal solution would be to have a directive that translates between date object and string value seamlessly. Probably could be done by decorating the existing Ng directive itself. Something to look into; we can always use your help; this is open source :-).
Meanwhile, you can create a defined property on your customSession
type constructor.
See "Custom Constructors" in the documentation. Such a property would wrap the
startDate
property (startDateAsString
?), parsing text in and formatting as string on the way out.
Here is a general purpose function to produce a Date wrapper property:
// Example: addDateWrapperProperty(SessionCtor, 'startDate', 'startDateAsString');
function addDateWrapperProperty(ctor, propName, wrapperPropName) {
Object.defineProperty(ctor.prototype, wrapperPropName, {
get: function () { return this[propName].toString(); },
set: function (value) { this[propName] = value; },
enumerable: true,
configurable: true
});
}
Use it to define your startDateAsString
wrapper property and then bind to this property when editing (bind to the real property for readonly display).
Because you don't want Breeze to serialize this, add it to the ctor AFTER registering that ctor with Breeze metadata as shown below.
I don't know for certain that this will give you the behavior you're looking for. I'd need to see your jsFiddle or plunkr to be sure. But I think it will do the trick. Let us know!
I'm certainly not saying this is the ultimate answer. I'm not sure what that answer is ... although I'm thinking about a directive as I said.
Hope this gets you out of the jam for now. Sorry it's such a PITA. Who knew Ng wouldn't understand Date objects?
Example
Here's an example extracted from an actual Breeze test:
///// Test it //////
var OrderCtor = function () { }; // do-nothing custom constructor
// register the ctor FIRST, then add the property
manager.metadataStore.registerEntityTypeCtor('Order', OrderCtor);
addDateWrapperProperty(OrderCtor, 'orderDate', 'orderDateAsString');
// create new order with a test date
var testDate = new Date(2014,0,1,13,30); // 1/1/2014 1:30 pm
var order = em.createEntity('Order', {
companyName: "test cust",
orderDate: testDate
});
// confirm can read the date through the wrapper property
expect(order.orderDate.value).to.equal(testDate.value,
"'order.orderDate' should return " + testDate);
expect(order.orderDateAsString).to.equal(testDate.toString(),
"'order.orderDateAsString' should return " + testDate.toString());
var testDate2 = new Date();
// update orderDate by way of the wrapper property
order.orderDateAsString = testDate2.toString();
// confirm the update worked
expect(order.orderDate.value).to.equal(testDate2.value,
"after update, 'order.orderDate' should return " + testDate2);
expect(order.orderDateAsString).to.equal(testDate2.toString(),
"after update, 'order.orderDateAsString' should return " + testDate2.toString());
// confirm it is not a breeze-tracked property
var propInfo = order.entityType.getProperty('orderDateAsString');
expect(propInfo).to.equal(null, "'Order.orderDateAsString' is not known to metadata ");
来源:https://stackoverflow.com/questions/26982624/angular-and-breeze-edit-date-object