I am trying to bind the value=".."-attribute from an <input>-field to a JsViews observable, so that changes made from a JS datepicker will get detected by the JsView framework.
Example
On initial rendering, the data-linked observedDate parameter is displayed in the <input>-field:
<input class="flatpickr-calendar" type="text" data-link="observedDate">
Then, selecting a new date using the flatpickr javascript tool, the new date will be stored in the value=".."-field:
<input class="flatpickr-calendar" type="text" data-link="observedDate" value="2017-05-09">
The problem
There is now a divergence between the date handled by observedDate and the value-attribute:
JsViews does not detect the change in the value-attribute.
Does anyone have some suggestion as of how to handle this situation? Thanks.
You need an event onChange update value observedDate.
For example, you can do so:
$(".flatpickr").flatpickr({
onChange: function(selectedDates, dateStr, instance) {
$.observable($.view(this.input).data).setProperty("observedDate", dateStr);
},
});
full code.
Update
Or you can create custom tag:
$.views.tags({
flatpickr: {
template: "<input/>",
onUpdate: false,
dataBoundOnly: true,
flatpickr: null,
isChange: false,
changeEvent: function (selectedDates, dateStr, instance) {
this.isChange = true;
this.update(dateStr);
this.isChange = false;
},
onDispose: function () {
if (this.flatpickr) {
this.flatpickr.destroy();
}
},
onAfterLink: function (tagCtx, linkCtx) {
var tag = this;
var props = tagCtx.props;
var options = {
defaultDate: tagCtx.args[0]
};
if (tag._.unlinked) {
if (!tag.linkedElem) {
tag.linkedElem = tag._.inline ? tag.contents("*").first() : $(linkCtx.elem);
}
$.each(props, function (key, prop) {
var option;
if (key.charAt(0) === "_") {
key = key.slice(1);
options[key] = prop;
}
});
options.onChange = $.proxy(tag.changeEvent, tag);
this.flatpickr = tag.linkedElem.flatpickr(options);
} else {
if (!this.isChange) {
this.flatpickr.setDate(options.defaultDate)
}
}
}
}
});
And use:
{^{flatpickr observedDate /}}
full code
Support flatpickr options:
{^{flatpickr observedDate _inline=true _maxDate='2018-05-01' _minDate='2017-05-01'/}}
full code
Related
I am using this Tiny Date Picker library to implement a range datepicker, I am using the NgZone, to run it outside the angular, using the runOutsideAngular() method, now I want to implement a blur event handler, so that when I click outside the calender the picker closes, but the angular is not firing the function when the div is blured because it is not detecting any changes as it is running outside the angular, any ideas for this?
my html
<div type="text" class="sp-datepicker-input" tabindex="1" (blur)='closeDatePicker()' [class.sp-datepicker-inputopen]="modalRangeOpen">
<div class="sp-datepicker-calendar"></div>
</div>
my ts.
ngAfterViewInit() {
this.zone.runOutsideAngular(() => {
const input = document.querySelector('sp-datepicker .sp-datepicker-input');
let eventType = 'select';
if (this.range) {
this.datePicker = DateRangePicker(input, {
startOpts: this.options,
endOpts: this.to_options
});
eventType = 'statechange';
} else {
this.datePicker = TinyDatePicker(input, this.options);
}
this.datePicker.on(eventType, (_, picker) => {
let date = picker.state.selectedDate;
if (this.range) {
date = {
start: picker.state.start,
end: picker.state.end
};
}
// here i am using the .run() method to capture the values,
this.zone.run(() => {
this.start_value = date.start;
this.end_value = date.end;
this.onChange(date);
});
return date;
});
});
}
closeDatePicker() {
this.modalRangeOpen = false;
}
This workaround did the trick
body.addEventListener('click', event => {
let isDatepicker = false;
event['path'].forEach(item => {
if (item.nodeName === 'SP-DATEPICKER') {
isDatepicker = true;
}
});
if (!isDatepicker) {
this.zone.run(() => {
this.closeDatePicker();
});
}
});
I have used vue-hotel-date-picker its working fine. the issue is when using disabled dates props its disabled the dates first time when initializing and update on calendar.but when i update disabled dates array on any button click event it updates the disabled dates array but not reflect or render in view component. I have debug it through vuejs chrome extension.
Here is an image when debugging
plugin link
Here is my HTML Code
<div class="box">
<h3>Check in only on saturday and minimum stay of 10 days</h3>
<DatePicker
DatePickerID="01"
:disabledDates = "disabledDates"
:enableCheckout="true"
:minNights="10"
:useDummyInputs="false"
placeholder="StartDate ► EndDate"
/>
</div>
<button #click="onChangeDisableDates()" > Change Disable Dates </button>
JS
<script>
import DatePicker from 'components/HotelDatePicker.vue';
export default {
components: {
DatePicker
},
data () {
return {
disabledDates : ['2017-08-18']
}
},
methods : {
onChangeDisableDates () {
this.disabledDates.push("2017-08-19");
}
}
};
</script>
I don't know how to figure out and solve this problem , it might be issue in this plugin,any help would be appreciated!
Write in computed: { } it will be updated then whenever there's a change.
import DatePicker from 'components/HotelDatePicker.vue';
export default {
components: {
DatePicker
},
data() {
newDisabledDates: null
}
computed: {
disabledDates() {
// write your disable date change logic or fetch from any other data var
if (this.newDisabledDates === null) {
//default logic
return {
disabledDates: ['2017-08-18']
}
} else {
// this.newDisabledDates would have been updated here if button clicked
return {
disabledDates: this.newDisabledDates
}
}
}
},
methods: {
onChangeDisableDates() {
this.newDisabledDates.push("2017-08-19");
}
}
};
disabledDates(date) {
var gDate = date.getDate();
var gMonth = date.getMonth();
var gYear = date.getYear();
for(var i=0;i<(this.disabled.length);i++) {
var myarr = this.disabled[i].split("-");
if(gDate == parseInt(myarr[2]) && gMonth == parseInt(myarr[1]) && gYear == parseInt(myarr[0])) {
return true;
}
else {
return false;
}
}
}
I'm looking for a method which makes a field invisible on js (i'm making a custom widget 'InvisibleIfEmptry').
I tried to override _check_visibility method when extending FormWidget.AbstractField class :
var core = require('web.core'),
form_common = require('web.form_common');
var InvisibleIfEmpty = form_common.AbstractField.extend({
start: function() {
this.on("change:effective_readonly", this, function() {
this._toggle_label();
this._check_visibility();
});
this.render_value();
this._toggle_label();
},
_check_visibility: function() {
if (this.get("effective_readonly"))
this.$el.toggleClass('o_form_invisible',true);
}
this.$el.toggleClass('o_form_invisible',false);
}
}, .....
but this makes invisible only the field's value, not the label.
my guess is to alter some of field_manager's values but i can't figure out which one ?
Thank you for your help :)
Here is my JS code for doing that :
odoo.define('myCustomModule', function(require)
{
'use strict';
var core = require('web.core'),
form_common = require('web.form_common'),
form_view = require('web.FormView');
form_common.AbstractField.include({
start: function() {
this._super();
// Check visibility logic below when content
// changes or the form swich to view mode
this.field_manager.on("view_content_has_changed", this, function() {
this._check_visibility();
});
this.on("change:effective_readonly", this, function() {
this._toggle_label();
this._check_visibility();
});
},
_check_visibility: function() {
// If the form is in view mode and the field is empty,
// make the field invisible
window.alert(this.);
if (this.field_manager.get("actual_mode") === "view" ) {
if(this.get("value") == false){
this.$el.toggleClass('o_form_invisible',true);
this.$label.toggleClass('o_form_invisible',true);
}else{
this.$el.toggleClass('o_form_invisible',this.get("effective_invisible"));
this.$label.toggleClass('o_form_invisible',this.get("effective_invisible"));
}
}else{
this.$el.toggleClass('o_form_invisible',this.get("effective_invisible"));
this.$label.toggleClass('o_form_invisible',this.get("effective_invisible"));
}
},
});
});
But this applies to all my modules.
Does Any one know how to get module/model name from AbstractField ?
I use JsViews + spectrumjs colorpicker and i had to create custom tag like this:
$.views.tags({
spectrum : {
template : "<input/>",
onAfterLink : function (tagCtx, linkCtx) {
var tag = this;
var props = tagCtx.props;
var options = {
color : tagCtx.args[0]
};
var linkedElem;
if (tag._.unlinked) {
if (!tag.linkedElem) {
tag.linkedElem = tag._.inline ? tag.contents("*").first() : $(linkCtx.elem);
}
linkedElem = tag.linkedElem;
$.each(props, function (key, prop) {
var option;
if (key.charAt(0) === "_") {
key = key.slice(1);
options[key] = prop;
}
});
this.linkedElem.spectrum(options);
}
},
onUpdate : function () {
return false;
},
onDispose : function () {
this.linkedElem.spectrum("destroy");
}
}
});
It works see example, but i need to dynamically update color.
In spectrumjs there is event move.spectrum and sign up on him like that:
tag.spectrum = tag.linkedElem.spectrum(options);
tag.spectrum.on("move.spectrum", $.proxy(tag.moveEvent, tag));
And add handlers:
moveEvent : function (e, val) {
// update model.color
console.log(val.toRgbString());
this.linkedElem.val(val.toRgbString());
},
onDispose : function () {
this.spectrum.off("move.spectrum", $.proxy(this.moveEvent, this));
this.spectrum.spectrum("destroy");
}
See example.
So I have not tried it, I can not track changes or apply changes to model.color becose color is base type string
Update
I made an example without use custom tag of how things should work.
Here is an update of your example page: https://jsfiddle.net/BorisMoore/g4vs23v1/5/
I changed the onAfterLink code as follows:
onAfterLink : function (tagCtx, linkCtx) {
var tag = this;
var props = tagCtx.props;
var options = {
color: tagCtx.args[0]
};
var linkedElem;
if (tag._.unlinked) {
if (!tag.linkedElem) {
tag.linkedElem = tag._.inline ? tag.contents("*").first() : $(linkCtx.elem);
}
linkedElem = tag.linkedElem;
$.each(props, function (key, prop) {
var option;
if (key.charAt(0) === "_") {
key = key.slice(1);
options[key] = prop;
}
});
tag.spectrum = linkedElem.spectrum(options);
//tag.spectrum.on("move.spectrum", $.proxy(tag.moveEvent, tag));
linkedElem.on("move.spectrum", $.proxy(tag.moveEvent, tag));
} else {
tag.linkedElem.spectrum("set", options.color);
}
},
Specifically I corrected the binding to move.spectrum as follows
linkedElem.on("move.spectrum", $.proxy(tag.moveEvent, tag));
And when color is updated observably, such as by changing the "rgb(...)" string in the textbox, the new value needs to be set on the spectrum tag, which happens on this line:
tag.linkedElem.spectrum("set", options.color);
So now you should have two-way binding between the input binding to color and the input binding to the {{spectrum}} tag.
There are many threads here for similar issues that I have read through and tried to apply to my situation being very new to all of this I haven't been able to figure it out I am afraid and was hoping for a little help
I need 2 instances of datepicker on my form with the javeascript alert if certain dates are selected. Using an example that i have found I am able to get one working but am unable name the other datepicker something unique in order to have the second one working as well
$(window).load(function(){
var Event = function (text, className) {
this.text = text;
this.className = className;
};
var events = {};
events[new Date("02/07/2014")] = new Event("Event01", "highlight");
events[new Date("02/26/2014")] = new Event("Event02", "highlight");
events[new Date("02/27/2014")] = new Event("Event03", "highlight");
$("#datepicker").datepicker({
beforeShowDay: function (date) {
var event = events[date];
if (event) {
return [true, event.className, event.text];
} else {
return [true, '', ''];
}
},
onSelect: function (date) {
var event = events[new Date(date)];
if (event) {
alert(event.text)
}
}
});
});//]]>
</script>
<body>
<input type="text" id="datepicker">
<input type="text" id="datepicker2">
</body>
Any help gratefully received
If you want to apply the same functions to both datepickers then you would be better off assigning them a class and using that to control them.
<input type="text" class="datepicker" />
$(".datepicker").datepicker({
beforeShowDay: function (date) {
var event = events[date];
if (event) {
return [true, event.className, event.text];
} else {
return [true, '', ''];
}
},
onSelect: function (date) {
var event = events[new Date(date)];
if (event) {
alert(event.text)
}
}
});