How to display custom validation for date picker in ngx-formly/bootstrap - angular8

I am creating dynamic UI/form using ngx-formly/bootstrap(not using material). I want to display datepicker control so I have displyed custom bsdatepicker control using ngx-bootstrap/datepicker. Now I want to do validations on this datepicker e.g IfI have from and to date then From date should not be less than current date or To Date should not be grater than from date. Any help will be appriciated.
//datepicker.html
<pre><input type="text"
id="dob-id"
class="form-control calendar"
placement="bottom"
bsDatepicker
[formlyAttributes]="field"
#dobDate="bsDatepicker"
[bsConfig]="bsConfig"
placeholder="YYYY-MM-DD"
[class.is-invalid]="showError" class="" style="width: 350px;">
took separate component for this and registered in app.modeul
//in scheema
{
key: 'date1',
type: 'bsdatepicker',
templateOptions: {
label :'From Date',
required: true,
},
},
{
key: 'date2',
type: 'bsdatepicker',
templateOptions: {
label :'To Date',
required: true,
},
},

The validation is handled by Formly so all you need is to just define validation along with its messages you may check our examples in the docs:
https://formly.dev/examples/validation/built-in-validations
https://formly.dev/examples/validation/custom-validation
https://formly.dev/examples/validation/validation-message

ngx-bootstrap is a wrong tag here, I think

Related

how to combine data from two columns in aurelia slickgrid

I have a aurelia slickgrid table with start date and end date and it is fine. Backend api response is in odata format. Now i want to make a new column called Status and status is calculated as :
<td class="col-xs-4 col-md-2">
<div>
<div if.bind="doesLicenseActivate(lic)">
Activates on ${lic.DateStart}
</div>
<div if.bind="didLicenseEnd(lic)">
Ended on ${lic.DateEnd}
</div>
<div if.bind="isLicenseCurrentlyActive(lic)">
Current License
</div>
<div if.bind="lic.IsCanceled">
Cancelled on ${lic.DateEnd}
</div>
</div>
Basically, those fucntions above such as doesLicenseActivate are bunch of Moment.js function doing some date caclulations. My column looks like:
/* Define grid Options and Columns */
private defineMembershipGrid() {
return this.columnDefinitionsMembershipHistory = [
{ id: "DateStart", name: "Start Date", field: "DateStart", formatter: Formatters.dateEuro, sortable: true, filterable: true, minWidth: 100, },
{ id: "DateEnd", name: "End Date", field: "DateEnd", formatter: Formatters.dateEuro, sortable: true, filterable: true, minWidth: 100, },
{ id: "Duration", name: "Duration", field: "Duration", formatter: this.DurationFormatter, sortable: true, filterable: true, minWidth: 100, },
// make a status column here
];
}
This is how it looks like:
And this is what i want to do, basically make a new Status column and it uses the values from first two columns (start and end date)
Just use a Custom Formatter, see Custom Formatter - Wiki it has the dataContext which is the item object of the entire row. You can use MomentJS to do your calculation and display "10 months" or "Current License" (I guess that last one would be a calculation and a switch/case). You can do anything you want in a Custom Formatter and it will be recalculated every time the grid re-render, if you change value of another cell it will also be recalculated. You might have problem to filter and sort though and in that case you might want to not show a filter and remove the sort.

Can I pass metadata through Vue Formulate's schema API without affecting input attributes?

The goal:
generate form fields from JSON/CMS
have a param in the JSON that allows two fields to sit next to each other on a single line
The solution so far:
I’m using Vue Formulate's schema API to generate fields. In Vue Formulate's options, I can conditionally add a class to the outer container based on a parameter in the context.
classes: {
outer(context, classes) {
if (context.attrs.colspan === 1) {
return classes.concat('col-span-1')
}
return classes.concat('col-span-2')
},
I’m using Tailwind, which requires no classname concatenation and actually want the default to be col-span-2, so if you’re inclined to copy this, your logic may vary.
With a few classes applied to the FormulateForm, this works really well. No additional wrapper rows required thanks to CSS grid:
<FormulateForm
v-model="values"
class="sm:grid sm:grid-cols-2 sm:gap-2"
:schema="schema"
/>
The schema now looks something like this:
[
{
type: 'text',
name: 'first_name',
label: 'First name',
validation: 'required',
required: true,
colspan: 1,
},
The problem/question
Vue Formulate’s schema API passes all attributes defined (other than some reserved names) down to the input element. In my case, that results in:
<div
data-classification="text"
data-type="text"
class="formulate-input col-span-1"
data-has-errors="true"
>
<div class="formulate-input-wrapper">
<label
for="formulate-global-1"
class="formulate-input-label formulate-input-label--before"
>
First name
</label>
<div
data-type="text"
class="formulate-input-element formulate-input-element--text"
>
<input
type="text"
required="required"
colspan="1" <--------------- hmm…
id="formulate-global-1"
name="first_name"
>
</div>
</div>
</div>
I recognize that I can name my attribute data-colspan so that I’m not placing a td attribute on an input, but I think of colspan as metadata that I don’t want applied to the template. Is there a way to prevent this from being applied to the input—perhaps a reserved word in the schema API that allows an object of metadata to be accessed via context without getting applied to v-bind="$attrs"?
The vue-formulate team helped me out on this one. Very grateful. Much love.
There is a way to prevent it from landing on the input, and that's to use the reserved outer-class property in the schema:
[
{
type: 'text',
name: 'first_name',
label: 'First name',
validation: 'required',
required: true,
'outer-class': ['col-span-1'],
},
This means that I don't need to do this at all:
classes: {
outer(context, classes) {
if (context.attrs.colspan === 1) {
return classes.concat('col-span-1')
}
return classes.concat('col-span-2')
},
vue-formulate supports replacing or concatenating classes via props. I managed to overlook it because I didn't recognize that everything you pass into the schema API is ultimately the same as applying a prop of that name.
Classes can be applied to several other parts of the component as well—not just the outer/container. More information here:
https://vueformulate.com/guide/theming/customizing-classes/#changing-classes-with-props

Vue - set v-model dynamically (with a variable containing a string)

I haven't been able to set v-model dynamically.
It works if I type explicitly:
<div class="form-group mr-3 mb-2">
<input type="text"
v-model="form[filters][firstlastname]"
>
</div>
But I want to loop through an object wherein I have string , like: 'form[filters][firstlastname]'
The parent has the form with properties:
data() {
return {
form: new Form({
filters: {
gender: [],
firstlastname: 'My firstlastname'
So, from the parent I pass down the form and filters into the child component, here is filters:
let formFilters = { filters: [
{
type: 'text',
property: 'form[filters][firstlastname]', // <-- string
placeholder: 'Name',
},
{
type: 'number',
property: 'paginate',
placeholder: 'Max rows'
},
]
}
Child component: (here I loop through the object and generate the input fields)
<div v-for="(filter,index) in formFilters.filters"
:key="`${index}_${filter.property}`"
>
<input
v-if="filter.type === 'text' || filter.type === 'number'"
:placeholder="filter.placeholder"
:type="filter.type"
v-model="filter.property" //<--- set the property
>
This doesn't work. The v-model just interprets it as a string and not a reference to a form property.
I tested other ways, like: v-model="``${[filter.property]}``" (single, not double ```` but it wont show in stackoverflow otherwise) and other crazy things but it isn't valid.
So how do I set v-model with a variable containing a string (so that it can be set dynamically)?
This is a very tricky problem....
You can access any property present in the data inside html template using 2 ways,
Referring to the property directly
Using $data
data() {
return {
firstlastname: 'Mr First last name'
}
}
so, in html template you can use either
<p>{{firstlastname}}</p>
or
<p>{{$data.firstlastname}}</p>
For your scenario $data can be used for primitive data types like string or number,
<input
v-if="filter.type === 'text' || filter.type === 'number'"
:placeholder="filter.placeholder"
:type="filter.type"
v-model="$data[filter.property]">
But this will not work for your second scenario where you are trying to access nested property of an object form.filters.firstlastname
You can access this property using the following notation $data[form][filters][firstlastname]
In your case, the for loop will result as $data[form.filters.firstlastname] or $data[[form][filters][firstlastname]] which will throw an exception
As suggested in the comments, try different approach or flatten the object. You can refer to this link to see how to flatten the object https://stackoverflow.com/a/25370536/2079271

Vue Tables 2 - perPageValues option not working correctly

I am using Vue Js v.2.4.4 and trying to configurate vue-tables-2 plugin.
I have a list of rows and I am trying to limit them with the perPageValues option, here is my options:
options: {
filterByColumn: false,
filterable:['nickname','email','reg_date','year'],
perPage:100,
perPageValues: [10,25,50,100,500,1000],
texts: {
filter: "Search:",
filterBy: 'Search by {column}',
count: ''
},
dateColumns: ['reg_date'],
dateFormat: 'DD-MM-YYYY',
datepickerOptions: {
showDropdowns: true,
autoUpdateInput: true,
},
pagination: { chunk:10, dropdown: false },
headings: {
id: 'ID',
reg_date: 'Registered',
nickname: 'Nickname',
email: 'Email',
year: 'Registration date',
number: 'Number'
}
}
Everything is working fine, but the list of limitation-values showing only the first two elements:
No errors were provided in the console and the table filtering through this combobox is working without any possible issues.
The only thing is, when I am using a small values in the perPageValues option like this:
perPageValues: [1,3,6,7,9,11,13],
The full list of values is shown and everything is working correctly:
I conducted an observation and found that every number after 20 are not showing at all (from time to time).
Can you please give some advice to know which thing could provoke this issue?
Is it possible to fix this without fixing a plugin sources e.t.c.?
p.s. I am using this vue component without any other settings or components, in the test mode so there is no plugins incompatibility of versions e.t.c.
Thanks!
it's possible that that happens because you do not have that amount of records
you can try this
in your css:
.VueTables__limit {
display: none;
}
this will make the default selector disappear
in your vue template adds a new select:
<select #change="$refs.table.setLimit($event.target.value)">
<option value="10">5</option>
<option value="10">10</option>
<option value="20">20</option>
</select>
add the reference in the table you are generating
<v-client-table ref="table" :options="yourOptions" :data="yourData" :columns="yourColumns" ></v-client-table>
JSfiddle:
https://jsfiddle.net/jfa5t4sm/1868/
This isn't an answer to the question but if anyone ends up here wondering how to turn off the "Records:" dropdown completely via the options, you can do it like this...
options: {
perPage: 5,
perPageValues: [],
}

How to show a checkbox in a dojo datagrid?

How to show a checkbox in a dojo datagrid?
I would suggest setting cellType to dojox.grid.cells.Bool, instead of the formatter.The formatter gives you much freedom, but also the responsibility of gathering the data from all the checkboxes (for all the rows) afterwards. Something like this as a structure-entry should do the trick:
{
name: "is awesome?",
width: "auto",
styles: "text-align: center",
type: dojox.grid.cells.Bool, editable: true
}
Please make sure to use a write-store (like ItemFileWriteStore) and not just a read-store, otherwise you will be disabled to actually check the checkbox :)
Use formatter function as described in Widgets Inside dojo.DataGrid
You can return new dijit.form.Checkbox from formatter function in dojo 1.4
You need the IndirectSelection plugin for the EnhancedGrid, here's a fiddle: http://jsfiddle.net/raybr/w3XpA/5/
You can use something like this, with Json
HTML
<table id="myGrid" dojoType="dojox.grid.DataGrid"
clientSort="true" autoHeight="true" autoWidth="true">
<script type="dojo/method">
showFields();
</script>
</table>
DOJO
showFields:function () {
dojo.xhrPost({
url:"/getFields.do",
timeout:2000,
handleAs:"json",
load:dojo.hitch(this, "displayInGrid")
});
},
displayInGrid:function (jsonResult) {
var dataStore = new dojo.data.ItemFileReadStore(
{ data:jsonResult }
);
var checkboxLayout = [
[
{name:'ID', field:"id" },
{name:'Value', field:"id", formatter:this.addCheckBox}
]
];
var grid = dijit.byId("myGrid");
grid.setStructure(checkboxLayout);
grid.setStore(dataStore);
},
addCheckBox:function (val) {
var checkbox = "<input type='checkbox' name='myfields' value='" + val + "/>";
return checkbox;
},
If you are trying to show a checkbox selector on each row of the grid you can follow this tutorial
http://dojotoolkit.org/documentation/tutorials/1.8/working_grid/demo/selector.php
If the type of the cell is a boolean, then its value is displayed as either the string true or false. If a check box is desired, setting the cellType to be dojox.grid.cells.Bool and marking it as editable will make a checkbox appear.
http://dojotoolkit.org/reference-guide/1.9/dojox/grid/DataGrid.html#editing-cells
From markup, do like this for the desired result:
<th field="booleanField" cellType="dojox.grid.cells.Bool" editable="true">Checkbox field</th>