Normal way to validate sap.m.DatePicker input looks like this:
new sap.m.DatePicker({
value : {
path : "someModel>/SomeDate",
type : new sap.ui.model.type.Date({}, {
minimum : new Date()
})
}
})
I have the problem, that the "minimum" date will depend on different other parameters.
Binding in a type seems not working (or I do something wrong?).
I would be happy to have a function like this:
new sap.m.DatePicker({
value : {
path : "someModel>/SomeDate",
type : new sap.ui.model.type.Date({}, {
minimum : "{someModel>/MinimumDate}"
})
}
})
Anyone an idea how to solve this?
I prefer to avoid the usage of id's to grab for a control in the controller.
I build the following solution. Maybe there is a better way?
Definition of data type:
jQuery.sap.declare("my.CallbackDateType");
sap.ui.model.type.Date.extend("my.CallbackDateType", {
constructor : function () {
sap.ui.model.type.Date.apply(this, arguments);
this.sName = "CallbackDateType";
},
validateValue : function(oValue) {
var that = this;
if (that.oConstraints.callback!==undefined) {
that.oConstraints.callback[0].call(that.oConstraints.callback[1], that);
}
return sap.ui.model.type.Date.prototype.validateValue.call(this, oValue);
}
});
Use like this:
new sap.m.DatePicker({
value : {
path : "model>/Date",
type : new my.CallbackDateType({}, {
minimum : new Date(),
callback : [oController.getMinimumDate, oController]
})
}
})
Related
I have this attributes data
for(var k = 0;k<this.form.fields.length;k++)
{
this.dynamic_fields.push({attribute_id:attributes[k].id,value: attributes[k].value})
}
this.$router.push({
path: '/api/search-temp',
query:{
attributes: this.encodedAttributes()
}
});
encodedAttributes() {
const queryAttributes =this.dynamic_fields;
if (queryAttributes) {
return typeof queryAttributes !== "string"
? btoa(JSON.stringify(queryAttributes))
: queryAttributes;
}
return "";
},
I have a attribute id and an attribute value so i want to pass this id and value to url so that i cab loop in my controller attributes array and get id and value :
localhost:8000..?attributes[]['attribute_id_1']=attributevalue1&attributes[]['attribute_id_2']=attributevalue2...
I'm redirecting like this :
this.$router.push({ path: '/search-list',query:
{
}
Issue is i want to pass this multidimentional array to url, anyother workaround for this is also highly appreciated
What you may try is to json stringify and encode the object before passing it to the $route query
function encodedAttributes() {
const queryAttributes = this.$route.query.attributes;
if (queryAttributes) {
return typeof queryAttributes !== "string"
? btoa(JSON.stringify(this.$route.query.attributes))
: queryAttributes;
}
return "";
}
function decodedAttributes() {
const attributes = this.$route.query.attributes;
if (typeof attributes === "string" && attributes.length) {
return JSON.parse(atob(attributes));
} else {
return attributes;
}
}
And pass as query parameters to the route
this.$router.push({
path: '/search-list',
query:{
attributes: this.encodedAttributes()
}
Then in the Controller you can decode the attributes value from request data to get the associated array
class MyController extends Controller
{
public function index(Request $request)
{
$request->attributes = is_array(
$requestAttributes = json_decode(base64_decode($request->attributes), true)
)
? $requestAttributes
: [];
//Do other processing as needed
}
}
Had used something similar in one of my projects can't get my hands on the code right now.
Probably you can use function to escape unicode characters in the encodedAttributes as well as decodedAttributes if need be
function escapeUnicode(str){
return str.replace(/[^\0-~]/g, c => '\\u' + ('000' + c.charCodeAt().toString(16)).slice(-4))
}
function encodedAttributes() {
const queryAttributes = this.$route.query.attributes;
if (queryAttributes) {
return typeof queryAttributes !== "string"
? btoa(escapeUnicode(JSON.stringify(this.$route.query.attributes)))
: queryAttributes;
}
return "";
}
function decodedAttributes() {
const attributes = this.$route.query.attributes;
if (typeof attributes === "string" && attributes.length) {
return JSON.parse(atob(escapeUnicode(attributes)));
} else {
return attributes;
}
}
You're trying to set a nested object to the query params, it's not possible... your route's query object must be a flat object.
Summarizing the only way for you to have something like this:
?attributes[]['attribute_id_1']=attributevalue1&attributes[]['attribute_id_2']=attributevalue2
Would be from a query object like this:
query: {
"attributes[]['attribute_id_1']": 'attributevalue1',
"attributes[]['attribute_id_2']": 'attributevalue2',
}
You should flatten this multidimensional array into an simples object and use it as your query object.
Here is an example...
From this:
const multiDimArr = [
['attribute_1', 'value1'],
['attribute_2', 'value2']
];
Into:
const myObject = {
attribute_1: 'value1',
attribute_2: 'value2'
}
A way to do so would be:
const multiDimArr = [
['attribute_1', 'value1'],
['attribute_2', 'value2']
];
const myObject = {};
multiDimArr.forEach(arr => {
myObject[arr[0]] = arr[1];
});
And then use the object as the query object, so your url will look like this:
?attribute_1=value1&attribute_2=value2
How can i force ui router to reload the resolves on my state without reloading the entire ui/controller since
I am using components and since the data is binded from the state resolve,
i would like to change some parameters (pagination for example) without forcing the entire ui to reload but just the resolves
resolve : {
data: ['MailingListService', '$transition$', function (MailingListService, $transition$) {
var params = $transition$.params();
var ml = params.id;
return MailingListService.getUsers(ml, params.start, params.count)
.then(function (result) {
return {
users: result.data,
totalCount: result.totalCount
}
})
}],
node: ['lists', '$transition$', function (lists, $transition$) {
return _.find(lists, {id: Number($transition$.params().id)})
}]
},
I would like to change $transition$.params.{start|count} and have the resolve updated without reloading the html.
What you requested is not possible out of the box. Resolves are only resolved, when the state is entered.
But: one way of refreshing data could be, to check for state parameter changes in $doCheck and bind them to the components by hand.
Solution 1
This could look something like this:
export class MyComponent {
constructor($stateParams, MailingListService) {
this.$stateParams = $stateParams;
this.MailingListService = MailingListService;
this.paramStart = null;
this.paramCount = null;
this.paramId = null;
this.data = {};
}
$doCheck() {
if(this.paramStart !== this.$stateParams.start ||
this.paramCount !== this.$stateParams.count ||
this.paramId !== this.$stateParams.id) {
this.paramStart = this.$stateParams.start;
this.paramCount = this.$stateParams.count;
this.paramId = this.$stateParams.id;
this.MailingListService.getUsers(this.paramId, this.paramStart, this.paramCount)
.then((result) => {
this.data = {
users: result.data,
totalCount: result.totalCount
}
})
}
}
}
Then you have no binding in the parent component anymore, because it "resolves" the data by itself, and you have to bind them to the child components by hand IF you insert them in the template of the parent component like:
<my-component>
<my-child data="$ctrl.data"></my-child>
</my-component>
If you load the children via views, you are obviously not be able to bind the data this way. There is a little trick, but it's kinda hacky.
Solution 2
At first, resolve an empty object:
resolve : {
data: () => {
return {
value: undefined
};
}
}
Now, assign a binding to all your components like:
bindings: {
data: '<'
}
Following the code example from above, where you resolve the data in $doCheck, the data assignment would look like this:
export class MyComponent {
[..]
$doCheck() {
if(this.paramStart !== this.$stateParams.start ||
this.paramCount !== this.$stateParams.count ||
this.paramId !== this.$stateParams.id) {
[..]
this.MailingListService.getUsers(this.paramId, this.paramStart, this.paramCount)
.then((result) => {
this.data.value = {
users: result.data,
totalCount: result.totalCount
}
})
}
}
}
And last, you check for changes in the child components like:
export class MyChild {
constructor() {
this.dataValue = undefined;
}
$doCheck() {
if(this.dataValue !== this.data.value) {
this.dataValue = this.data.value;
}
}
}
In your child template, you access the data with:
{{ $ctrl.dataValue | json }}
I hope, I made my self clear with this hack. Remember: this is a bit off the concept of UI-Router, but works.
NOTE: Remember to declare the parameters as dynamic, so changes do not trigger the state to reload:
params: {
start: {
dynamic: true
},
page: {
dynamic: true
},
id: {
dynamic: true
}
}
I am using mongoosastic npm module. While truncating index I am getting
TypeError: Unable to build a path with those params. Supply at least index
The code I'm using
For Truncate :
var tagModelJS = require('../DaoModel/TagModel.js');
var TagModel = tagModelJS.getTagModel();
TagModel.esTruncate(function (err) {
if (err) {
console.log("ERROR : while removing data from elastic search.")
throw err;
}
});
TagModel :
var TAGS;
module.exports = {
createSchemaAndGetModel : function (mongoose, mongoosastic, Schema) {
//create schema
var tagSchema = new Schema({
tagDetail : String,
userIds : [], //list of user ids
tagName : {
type : [String],
es_indexed : true
} // field level
});
tagSchema.plugin(mongoosastic)
//create model
TAGS = mongoose.model('TAGS', tagSchema);
console.log("Tag model ready....");
},
getTagModel : function () {
return TAGS;
}
};
Any help would be greatly appreciated.
I have this Parse.Object that I want to save to the server, but I'd like to whitelist the attributes of this object that get saved.
Parse.Object.extend('someObject', {
defaults: {
foo: 1,
bar: 2,
computedProperty: function() {
return this.get('foo') + this.get('bar')
}
},
get: function(attr) {
var value = Parse.Object.prototype.get.call(this, attr)
return _.isFunction(value) ? value.call(this) : value
}
})
As you can see, this object has a computed property among its attributes. I would like to filter out the computedProperty when I save this Parse.Object. Is that possible?
So, we've figured out a way to filter the list of attributes that get saved.
If you wanna do it, you have to override a private, undocumented method on the Parse.Object called _getSaveJSON, so the complete model above would be:
Parse.Object.extend('someObject', {
defaults: {
foo: 1,
bar: 2,
computedProperty: function() {
return 1+2
}
},
get: function(attr) {
var value = Parse.Object.prototype.get.call(this, attr)
return _.isFunction(value) ? value.call(this) : value
},
_getSaveJSON: function() {
var model = this
var json = _.clone(_.first(this._opSetQueue))
Parse._objectEach(json, function(op, key) {
json[key] = op.toJSON();
});
var whitelistedAttributes = ['foo', 'bar']
return _.pick(json, whitelistedAttributes)
}
})
Just a little hack for validating against a kendo.data.Model
So instead of adding the HTML5 required attribute to each input field manually
this little hack gets all the validation rules that you defined in your Model and
add them as attributes to the appropriate field. Not fully tested just a quick hack. According to Kendo the validation rules don't get processed if you are using MVVM, but they do if for example you bind the Dataource directly to a grid.
Code:
I just put this code in a file called definevalidation.js
function getValidationAttributesFromModel(myFields) {
var myValidatedFields = [];
var obj = null;
$.each(myFields, function(fieldName) {
if (this.validation) {
var obj = {
fieldName : fieldName,
validation : this.validation
};
myValidatedFields.push(obj);
}
});
addValidationAttributes(myValidatedFields);
}
function addValidationAttributes(myValidatedFields) {
$.each(myValidatedFields, function(index) {
$('#' + this.fieldName).attr(this.validation);
});
}
Usage:
If ParentDS is your datasource then in your form code just use
getValidationAttributesFromModel(ParentDS.options.schema.model.fields)
Sample Model:
mydatamodel = kendo.data.Model.define({
id : "__KEY",
fields : {
__KEY : {
type : "string"
},
__STAMP : {
type : "number"
},
ID : {
editable : false,
nullable : true
},
firstName : {
type : "string",
validation : {
required : true
}
},
middleName : {
type : "string"
},
lastName : {
type : "string"
}
}
});