I have a form that is populated by data received from an API request to my backend.
I am using v-model to bind the data to the fields (for example):
<input type="text" v-model="fields.name">
Everything works just fine. But when it comes to Buefy datepicker I get the following warning:
Invalid prop: type check failed for prop "value". Expected Date, got String.
This is correct since this is the value I get back from Laravel is "2019-02-01 00:00:00". I am trying to parse this String to a Date using the Buefy property date-parser but with no luck:
<b-datepicker
:date-parser="(date) => new Date(Date.parse(date))"
v-model="fields.budget_date"
:first-day-of-week="1"
placeholder="DD/MM/YYYY"
name="order_date"
editable>
</b-datepicker>
Update:
This is the data object:
data() {
return {
csrf: document.querySelector('meta[name="csrf-token"]').content,
fields: {},
errors: {},
success: false,
loaded: true,
loading: false,
}
Then I use Axios.get to fetch the data from the server and assign them to the fields object like so:
this.fields = response.data;
This is how is see the fields.budget_date in Vue DevTools:
Any idea how to overcome this? Thank you in advance.
I just had this problem in a wrapper component around Buefy's b-datepicker component.
The solution can be derived from christostsang's answer which is to pass in the initial value wrapped in new Date().
My wrapper component prop type looks like this:
initialValue: {
type: Date,
required: false,
default: () => undefined,
},
and it is used like this:
<my-datepicker
:initial-value="new Date(something.renews_on)"
></my-datepicker>
I'm using mostly the default props from b-datepicker, but my wrapper component is using this:
<b-datepicker
v-model="value"
:initial-value="initialValue"
:placeholder="placeholder"
:name="name"
:date-formatter="dateFormatter"
:date-parser="dateParser"
:date-creator="dateCreator"
... etc
...
dateFormatter: {
type: Function,
required: false,
default: date => date.toLocaleDateString(),
},
dateParser: {
type: Function,
required: false,
default: date => new Date(Date.parse(date)),
},
dateCreator: {
type: Function,
required: false,
default: () => new Date(),
},
You can investigate the default props here: https://buefy.org/documentation/datepicker
Finally figured it out.
The warning is pretty clear: Don't use a string here, use a Date object.
So after getting the response from the server, I parsed the string value into Date object and then bind it to v-model:
this.fields.budget_date = new Date(this.fields.budget_date)
So now I get this into Vue DevTools:
As you can see the budget_date is of the correct Date format, unlike created_at which is a string.
Parser function (:date-parser) gives you the correct Date object during user date selection.
What I wanted was to set the v-model value based on the data stored in my database. And for the b-datepicker to work that needs to be Date object, not String.
Related
I'm building conditional form with vue and stuck on how conditionally validate input field based on the previous users choice. I'll appreciate any help.
in the form I have dropdown menu with payment choices (terminal, payconiq, cash etc).
Second input field is the link user need to add. If user choose terminal, he should add to link input an IP Address. If not - url address.
I receive a paymentId from options with #click, send it to the store and get it from the store with computed property.
The problem is that my vuelidate does not read the condition
const typefromStore = computed(() => paymentStore.paymentType) // here I get typeId from store
const validations = {
description: { required },
type: { required },
link: {
required,
type: typefromStore.value === 1? ipAddress : url // always checks for url and give an error if I need to input IP address
},
}
I read documentation, but I didn't find how to check second input field based on the value of the previous. Only cases when previous field is invalid. But data from dropdown list is always valid.
I need to use the value of 'type' somehow to check conditionally value of link.
Found the solution. May be will help someone. Needed to put validation in computed. No store needed
let newMethod = reactive({
instanceId: 1,
description: '',
type: -1,
link: '',
active: true,
})
const rules = computed(() => {
const localRules = {
description: { required },
type: { required },
link: {},
}
if (newMethod.type === 1) {
localRules.link = {
ipAddress,
}
}
else {
localRules.link = {
url,
}
}
return localRules
})
const v$ = useVuelidate(rules, newMethod, { $autoDirty: true })
I need a default value for a field that I get from a datasource, and bind to that field using an observable. (That value can then be updated if needed by the user using a treeview). I can read the initial remote datasource, build the observable and bind the value to the field. I can then pop up a dialog, show a tree and return the values. What I cant seem to do is set the value of the observable because it is based on a datasource, and therefore seems to be a much bigger and more complicated json object which I am viewing in the console. I have also had to bind differently in order to get that working as well as shown below.
Below if just a snippet, but should give an idea. The remote data source returns just: {"name":"a name string"}
<p>Your default location is currently set to: <span id="repName" data-bind="text: dataSource.data()[0].name"></span></p>
<script>
$(document).ready(function () {
var personSource2 = new kendo.data.DataSource({
schema: {
model: {
fields: {name: { type: "string" }}
}
},
transport: {
read: {
url: "https://my-domain/path/paultest.reportSettings",
dataType: "json"
}
}
});
personSource2.fetch(function(){
var data = personSource2.data();
console.log(data.length); // displays "1"
console.log(data[0].name); // displays "a name string"
var personViewModel2 = kendo.observable({
dataSource: personSource2
});
var json = personViewModel2.toJSON();
console.log(JSON.stringify(json));
observName1 = personViewModel2.get("dataSource.data.name");
console.log("read observable: "+observName1);
kendo.bind($(''#repName''), personViewModel2);
});
After a lot of playing around, I managed to get the value to bind using:
data-bind="text: dataSource.data()[0].name"
but I can't find this documented anywhere.
Where I output the observable to the console, I get a great big object, not the simple observable data structure I was expecting. I suspect I am missing something fundamental here!
I am currently just trying to read the observable above, but can't get it to return the string from the json source.
personSource2.fetch(function(){
var data = personSource2.data();
console.log(data.length); // displays "1"
console.log(data[0].name); // displays "Jane Doe"
var personViewModel2 = kendo.observable({
dataSource: personSource2
});
var json = personViewModel2.toJSON();
console.log(JSON.stringify(json));
observName1 = personViewModel2.get("dataSource.data()[0].name");
console.log("read observable: "+observName1);
personViewModel2.set("dataSource.data()[0].name","Another Value");
observName1 = personViewModel2.get("dataSource.data()[0].name");
console.log("read observable: "+observName1);
kendo.bind($(''#repName''), personViewModel2);
});
I'm trying to use Kendo UI MultiSelect to select some stuff from an API. The API won't return all items because they are too much. It will only return those that contains the searchTerm.
I'm trying to figure out how to send the input text in a Kendo UI Multiselect. When I say the input text, I mean what the user typed in the input before selecting anything from the list. That text has to be passed on to the DataSource transport.read option.
See this Codepen to understand
https://codepen.io/emzero/pen/NYPQWx?editors=1011
Note: The example above won't do any filtering. But if you type "bre", the console should log searching bre.
Use the data property in the read transport options, this allows you to modify the query being sent by returning an object that will later on be serialized in the request.
by default read are GET requests so it will be added to the queryString of your url specified.
If it were to be a POST it would be added to the POST values.
<div id="multiselect"></div>
<script>
$('#multiselect').kendoMultiSelect({
dataTextField: 'first_name',
dataValueField: 'id',
filter: "startswith",
dataSource: {
serverFiltering: true, // <-- this is important to enable server filtering
schema: {
data: 'data'
},
transport: {
read: {
url: 'https://reqres.in/api/users',
// this callback allows you to add to the request.
data: function(e) {
// get your widget.
let widget = $('#multiselect').data('kendoMultiSelect');
// get the text input
let text = widget.input.val();
// what you return here will be in the query string
return {
text: text
};
}
}
}
}
});
</script>
I am attempting to develop a Mobile app using Kendo Mobile's MVVM and JayData Data Access Library. I have run into an issue that I have worked on for about a week now with no luck. I am looking for a simple example consisting of Kendo two way binding using a model that is created by JayData's (asKendoDataSource) having an inverseProperty navigation property. I am not sure that JayData kendo.js Module supports models containing inverseProperty and in the process of testing, even after getting the data to save with the relationship, retrieval of the same record does not pull the relational data back into the viewmodel.
Can anyone provided a simple example of Saving and Retrieving such a model using the webSql provider?
Any help is greatly appreciated.
JayData Models (simplified):
//Expense Category Model
$data.Entity.extend('data.types.ExpenseCategory', {
Id: { type: 'Edm.Guid', key: true },
CategoryName: { type: 'string', required: true, minLength: 3, maxLength: 26 },
Expenses: { type: Array, elementType: "data.types.Expense", inverseProperty: "Category" }
});
//Expense Model
$data.Entity.extend('data.types.Expense', {
Id: { type: 'Edm.Guid', key: true },
ExpenseDescription: { type: 'string', required: true },
Category: { type: "data.types.ExpenseCategory", inverseProperty: "Expenses" }
});
// Entity Context
$data.EntityContext.extend('data.types.DbContext',
{
ExpenseCategories: { type: $data.EntitySet, elementType: data.types.ExpenseCategory },
Expenses: { type: $data.EntitySet, elementType: data.types.Expense },
});
// Database Context
data.context = new data.types.DbContext({ name: 'sqLite', databaseName: 'cDb' });
Kendo Viewmodel (simplified):
views.expenseCategoryPicker = kendo.observable({
app: null,
categories: db.context.ExpenseCategories.asKendoDataSource(),
expense: null,
itemClick: function(sender) {
var expense = views.expenseCategoryPicker.expense;
expense.set('Category', sender.data);
...add/update logic
expense.sync();
},
loadExpense: function(dataItem) {
views.expenseCategoryPicker.set('expense', undefined);
views.expenseCategoryPicker.set('expense', dataItem);
},
});
EDIT
I figured out why the data won't save and a work around. There is a bug in JayData's kendo.js module when using the Kendo MMVM binding and inverseProperty relationships. They(JayData) simply don't support their own Attach method when an object relationship is being set through their Kendo module. Therefor when you call Kendo's SET on the model passing in the related Object the Entity state on the Object being passed in is set to 20 (New) and JayData tries to create a new record and in my case failing due to primary key conflict. The Attach method sets the Entity state to unmodified.
I know there is probably a more elegant way to fix this in JayData's code, but for me simply adding the following line right before I use the Kendo set method to set the object relationship allows the record to be saved without error.
itemClick: function(sender) {
var expense = views.expenseCategoryPicker.expense;
//manually set the state so SQL won't try to create a new record
sender.data.innerInstance()._entityState = 10;
expense.set('Category', sender.data);
...
Subsequent reads require the Include('model') method to load the relational data as mentioned by Robesz (THANK YOU)
It would be nice to see JayData fix the data save issue in their Kendo module.
JayData doesn't load the related entities by default, you have to use the include() operator:
data.context.Expenses.include('Category').toArray(...)
The parameter of the include should be the name of the navigation property.
I would like to be able to validate single fields at a time in my forms using backbone forms and backbone validation, however I am having problems getting this to work if I put my requirements in the model validation, rather than the schema.
My model is:
class Event extends Backbone.Model
url: ->
'/events' + (if #isNew() then '' else '/' + #id)
validation:
title:
required: true
start_date:
required: true
end_date:
required: true
schema: ->
title:
type: "Text"
start_date:
type: "DateTime"
title: "Start Date"
DateEditor: "DatePicker"
end_date:
type: "DateTime"
title: "End Date"
DateEditor: "DatePicker"
The code in my View that uses these is
class Events extends Backbone.View
...
initialize: ->
#form = new Backbone.Form(model: #model).render()
Backbone.Validation.bind #form;
validateField: (field) ->
#form.on "#{field}:change", (form, fieldEditor) =>
#form.fields[field].validate()
render: ->
...
#validateField for field of #form.fields
...
However, my problem is that it only seems to validate if I move the required: true into the schema like so:
schema: ->
title:
type: "Text"
validators: ["required"]
However I'd rather not do this since, backbone.validation has a broader range of built-in validators which I would like to make use of outside this example.
I've noticed that backbone-forms states
There are 2 levels of validation: schema validators and the regular built-in Backbone model validation. Backbone Forms will run both when either form.commit() or form.validate() are called.
However I'm not sure it's running the regular validation when I validate the individual fields? The reasoning behind wanting to do this is that when a user starts creating an event I do not want to validate fields that they are yet to fill in.
Is there any way I can still validate individual fields without having to move the validation into the schema?
Thanks in advance.
======= UPDATE =======
On looking at the form editors source code for individual fields, the validate function is as so:
validate: function() {
var $el = this.$el,
error = null,
value = this.getValue(),
formValues = this.form ? this.form.getValue() : {},
validators = this.validators,
getValidator = Form.helpers.getValidator;
if (validators) {
//Run through validators until an error is found
_.every(validators, function(validator) {
error = getValidator(validator)(value, formValues);
return error ? false : true;
});
}
return error;
},
It does not appear to use the model validation, so I wonder how I can incorporate this?