What im trying to achieve is:
when i select the option "Alle openstaande" (result_id = 0), i want to select all these result_ids: [-1,-2,-3,-5,-7,-8,-11,-12] and deselect result_id 0.
var mergedResults returns a array of the result_ids that need to be selected
i cant figure out how i can add to the currently selected options via the methods
my blade file contains:
<dd-results
naam="resultcodes-select"
v-model="selected.resultcodes"
:select-all="true"
:multiple="true"
:openstaande="true"
:include-ids="true"
:project-id="selected.project"
title="#lang('rapportage.resultcode')"
:include-negative="true"
return-key="result_id"
>
</dd-results>
my vue file:
<template>
<span>
<label v-if="title">{{title}}</label>
<v-select
:options="results"
label="naam"
:placeholder="placeholderText"
:close-on-select="closeOnSelectValue"
:disabled="isDisabled"
:multiple="multiple"
:value="value"
#input="handleInput($event)"
:loading="isLoading"
:reduce="reduceKey"
>
<div slot="no-options">{{geenOptiesTekst}}</div>
</v-select>
</span>
</template>
<script>
import vSelect from "vue-select";
import Language from "../../classes/Language";
export default {
name: 'dd-results',
components: {
'v-select': vSelect
},
props: {
placeholder: {
type: String,
default: null
},
closeOnSelect: {
type: Boolean,
default: true
},
isDisabled: {
type: Boolean,
default: false,
},
// Meerdere waarden selecteren
multiple: {
type: Boolean,
default: false
},
openstaande: {
type: Boolean,
default: false
},
value: {
default: null
},
// Wel/geen 'Alle projecten' placeholder
selectAll: {
type: Boolean,
default: false
},
projectId: {
default: null,
required: true
},
title: {
type: String,
default: null
},
includeIds: {
type: Boolean,
default: false
},
// Wel / niet negatieve resultcodes tonen
includeNegative: {
type: Boolean,
default: false
},
// Als gevuld: alleen deze waarde teruggeven, anders volledig object
returnKey: {
type: String,
default: null,
},
excludeTypes: {
type: Array,
}
},
data() {
return {
language: new Language,
results: [],
isLoading: false,
}
},
created() {
var self = this;
this.language.set(lan);
},
methods: {
reduceKey(option) {
return this.returnKey != null ? option[this.returnKey] : option;
},
handleInput($event) {
this.$emit('input', $event);
if($event.includes(0)) {
this.addOpenstaande($event);
}
},
addOpenstaande(value) {
var openstaandeResult = [-1,-2,-3,-5,-7,-8,-11,-12];
var mergedResults = [... new Set (value.concat(openstaandeResult))];
const removeIndex = mergedResults.indexOf(0);
if (removeIndex > -1) {
mergedResults.splice(removeIndex, 1);
}
this.reset(mergedResults);
console.log(mergedResults);
},
reset(selected=false) {
// 1. verwijder de geselecteerde itemboxes
console.log(this.$el,$(this.$el).find('.vs__selected'));
$(this.$el).find('.vs__selected').remove();
setTimeout(() => {
// 2. herstel de placeholder
$(this.$el).find('.vs__selected-options input').attr('placeholder', this.placeholderText);
}, 100);
if(selected !== false) {
}
}
},
computed: {
// Tekst in dropdown bij geen opties
geenOptiesTekst() {
return this.language.trans('app', 'no_results');
},
// Bepaal placeholder tekst. Is afhankelijk van selectAll optie. Eigen placeholder overruled altijd.
placeholderText() {
if(this.placeholder != null) {
return this.placeholder;
}
else if(this.selectAll) {
return this.language.trans('rapportage', 'resultcode_alle');
} else {
return this.language.trans('rapportage', 'resultcode_selecteren');
}
},
// Bij mogelijkheid tot selecteren van meerdere projecten, standaard niet sluiten na selectie
closeOnSelectValue() {
if(this.multiple) {
return false;
} else {
return this.closeOnSelect;
}
}
},
watch: {
'projectId'(newVal) {
if(this.value != null) {
if(this.value.length != null) {
this.value.length = 0;
}
}
var self = this;
if(newVal != null) {
self.isLoading = true;
// Results opvragen en dropdown vullen
axios.get('/projecten/'+newVal+'/results').then(result => {
self.results = Object.values(result.data);
console.log(self.results);
for (var i = 0; i < self.results.length; i++) {
// Als negatieven gefilterd moeten en index negatief is: verwijderen
if(self.results[i].result_id < 0 && !this.includeNegative) {
self.results.splice(i, 1);
i--; // Index terugzetten door verwijderen item
continue;
}
// Als type in excludeTypes: verwijderen
if (this.excludeTypes) {
if (this.excludeTypes.indexOf(self.results[i].type) > -1) {
self.results.splice(i, 1);
i--;
continue;
}
}
}
for (var i = 0; i < self.results.length; i++) {
if (self.includeIds) {
// verander "naam" in "(result_id) naam"
self.results[i].naam = "(" + self.results[i].result_id + ") " + self.results[i].naam;
}
}
if(this.multiple === true && this.openstaande) {
self.results.unshift({
result_id: 0,
naam: this.language.trans('app', 'alle_openstaande')
})
}
}).catch(error => {
console.log(error);
}).then(data => {
self.isLoading = false;
})
} else {
this.results = [];
}
}
}
}
</script>
<style>
select:required:invalid {
color: gray;
}
.vs--disabled .vs__dropdown-toggle, .vs--disabled .vs__clear, .vs--disabled .vs__search, .vs--disabled .vs__selected, .vs--disabled .vs__open-indicator {
background-color: #D3D3D3;
color: #808080;
}
option {
color: black;
}
.vs__dropdown-toggle {
background: #fff;
}
</style>
i was able to make this work via the $emit in handleInput($event). (it seems so obvious now but i had no idea what this.$emit('input', $event); did at the time)
i changed these three methods:
handleInput($event) {
this.$emit('input', $event);
if($event.includes(0)) {
this.addOpenstaande($event);
}
},
addOpenstaande(value) {
var openstaandeResult = [-1,-2,-3,-5,-7,-8,-11,-12];
var mergedResults = [... new Set (value.concat(openstaandeResult))];
const removeIndex = mergedResults.indexOf(0);
if (removeIndex > -1) {
mergedResults.splice(removeIndex, 1);
}
this.$emit('input', mergedResults);
},
reset(selected=false) {
// 1. verwijder de geselecteerde itemboxes
$(this.$el).find('.vs__selected').remove();
setTimeout(() => {
// 2. herstel de placeholder
$(this.$el).find('.vs__selected-options input').attr('placeholder', this.placeholderText);
}, 100);
}
Related
I am new with Knockout js, i have checkbox and return value with condition.
I want change return value null if condition true, but i dont know how:
isChecked: ko.computed(function () {
return quote.paymentMethod() ? quote.paymentMethod().method : 'payu';
}),
isCheckedToShowTooltip: function () {
$(".loading-mask").addClass("hide");
if($(".payment-method").length == 0) {
if ($(".multiple_payment_method").length == 0) {
$(".billing-address-list").before('<h4 class="multiple_payment_method"><span>Datos de envío</span></h4>');
$(".block.items-in-cart.active div.title").addClass("hide");
$(".block.items-in-cart").before('<h4 class="multiple_payment_method"><span>Resumen de tu compra</span></h4>');
$("#checkout-payment-method-load").before('<h4 class="multiple_payment_method"><span>Método de pago</span></h4>');
}
if ($(".multiple_payment_method").length == 3) {
this.isChecked() = null; //<----------------Here not work
}
}
if(quote.paymentMethod()) {
if($("#seccion-payu-below").length > 0) {
$("#seccion-payu-below").remove();
}
if($("#seccion-efecty-below").length > 0) {
$("#seccion-efecty-below").remove();
}
switch(quote.paymentMethod().method) {
case "payu":
$('#initial-payu-container').remove();
$('#checkout-payment-method-load').removeClass('container-initial');
$("#payment-methods-group-list" ).after("<div id='seccion-payu-below'>" + $("#seccion-payu").html() + "</div>");
$("#seccion-payu-below button").removeAttr("data-bind data-posicion data-origen");
if($("#seccion-payu button").hasClass("disabled")) {
$("#seccion-payu-below button").attr('disabled','disabled').addClass("disabled");
} else {
$("#seccion-payu-below button").removeAttr('disabled','disabled').removeClass("disabled");
}
$("#seccion-payu-below button").attr({ id: "button_payu_below", type: "button", onclick: "submitPaymentMethod('" + quote.paymentMethod().method + "');" });
if($('#payu').is(':checked')) {
$('#seccion-payu-below').show();
}
break;
case "efecty":
$('#initial-payu-container').remove();
$('#checkout-payment-method-load').removeClass('.container-initial');
$("#payment-methods-group-list" ).after("<div id='seccion-efecty-below'>" + $("#seccion-efecty").html() + "</div>");
$("#seccion-efecty-below button").removeAttr("data-bind data-posicion data-origen");
if($("#seccion-efecty button").hasClass("disabled")) {
$("#seccion-efecty-below button").attr('disabled','disabled').addClass("disabled");
} else {
$("#seccion-efecty-below button").removeAttr('disabled','disabled').removeClass("disabled");
}
$("#seccion-efecty-below button").attr({ id: "button_efecty_below", type: "button", onclick: "submitPaymentMethod('" + quote.paymentMethod().method + "');" });
if($('#efecty').is(':checked')) {
$('#seccion-efecty-below').show();
}
break;
}
}
},
I tried mentioned condition and not work
And i know read and write properties but i do not know if this is my case
Any ideas? Thanks!
Thanks epascarello i edit condition, and solve the problem, add new validation for that:
isChecked: ko.computed(function () {
if (quote.paymentMethod()) {
return quote.paymentMethod().method
} else if (!rendererList._latestValue.some(item => item.type === 'efecty')) {
return 'payu';
} else {
$('#checkout-payment-method-load').removeClass('container-initial');
return null;
}
}),
Grettings!
I created a custom timer component, but I got errors about vuex store.
This component starts a timer when it's created and put into the store, then each minute it increments the time. If the person leaves the page like the timer is in the store, the time is saved and when the person comes back to the page, the timer resume by itself.
This is my component
<template>
<div>
<v-icon v-if="timer.visibility" :color="timeColor" #click="changeTimer">
{{ $icons.clock }}
</v-icon>
</div>
</template>
<script>
export default {
props: {
value: {
type: Number,
required: true
},
id: {
type: Number,
default: null
},
type: {
type: String,
default: null
}
},
data() {
return {
timer: {
actif: false,
visibility: false,
timeOut: null,
dateDebut: null,
id: 0
}
}
},
computed: {
listeTimer() {
return this.$store.state.listeTimerPointage
},
timeColor() {
return this.timer.actif ? 'green' : 'red'
},
count: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
},
beforeDestroy() {
this.stopTimer()
},
created() {
let precedentTimer = null
if (this.id > 0) {
if (this.listeTimer.length > 0) {
precedentTimer = this.listeTimer.filter((f) => f.id === this.id)
}
} else {
this.timer.id = 0
}
this.startTimer(precedentTimer)
},
methods: {
// Start le timer
startTimer(precedentTimer) {
if (precedentTimer !== null) {
this.timer = precedentTimer
this.count = precedentTimer.count
} else {
this.count = 1
this.timer.dateDebut = new Date()
if (this.timer.timeOut === null) {
this.timer.actif = true
this.timer.visibility = true
this.timer.timeOut = setTimeout(() => {
this.timerBoucle()
}, 60000)
}
}
// this.listeTimer.push(this.timer)
this.$store.commit('addListeTimerPointage', this.timer)
},
// Arrete le timer
stopTimer() {
this.timer.actif = false
clearTimeout(this.timer.timeOut)
},
// Met en place la boucle toute les 1 minutes
timerBoucle() {
const now = new Date()
const diff = now - this.timer.dateDebut
this.count += Math.round(diff / 60000)
this.timer.dateDebut = new Date()
this.timer.timeOut = setTimeout(() => {
this.timerBoucle()
}, 60000)
},
// Modifie l'état du timer
changeTimer() {
this.timer.actif = !this.timer.actif
if (!this.timer.actif) {
clearTimeout(this.timer.timeOut)
} else {
this.timer.dateDebut = new Date()
this.timer.timeOut = setTimeout(() => {
this.timerBoucle()
}, 60000)
}
}
}
}
</script>
I indeed mutate a state, but I don't think I change the state directly
And this is the store:
addListeTimerPointage(state, data) {
state.listeTimerPointage.push(data)
},
deleteTimer(state, data) {
const newArray = state.listeTimerPointage.filter(
(item) => item.id !== data
)
state.listeTimerPointage = newArray
}
Thanks for your help
I have a component with typing text, this effect add/remove word and write new word:
<template>
<span
id="textCode"
contenteditable="true"
spellcheck="false"
style="width: 800px"
v-text="displayText.join('')"
/>
</template>
<script>
export default {
props: {
speed: {
type: Number,
default: 100
},
deleteSpeed: {
type: Number,
default: 30
},
nextWordInterval: {
type: Number,
default: 1200
},
words: {
type: Array,
default: null
}
},
data () {
return {
displayText: [],
currentWord: '',
wordIdx: 0,
timeoutSpeed: null,
isWaitingNextWord: false
}
},
mounted () {
this.start()
},
methods: {
start () {
if (this.words && this.words.length > 0 && !document.querySelector('#textCode').contains(document.activeElement)) {
this.currentWord = this.words[this.wordIdx].split('')
this.timeoutSpeed = this.speed
this.animate = setTimeout(this.type, this.timeoutSpeed)
}
},
type () {
if (this.currentWord.length > 0) {
this.displayText.push(this.currentWord.shift())
// if done typing, wait for a while
} else if (!this.isWaitingNextWord && this.currentWord.length === 0 && this.displayText.length === this.words[this.wordIdx].length) {
this.timeoutSpeed = this.nextWordInterval
this.isWaitingNextWord = true
// if done typing, then delete
} else if (this.currentWord.length === 0 && this.displayText.length > 0) {
this.timeoutSpeed = this.deleteSpeed
this.displayText.pop()
// if done typing & deleting
} else if (this.currentWord.length === 0 && this.displayText.length === 0) {
// change words
if (this.wordIdx < (this.words.length - 1)) {
this.wordIdx++
} else {
// reset
this.wordIdx = 0
}
this.timeoutSpeed = this.speed
this.isWaitingNextWord = false
this.currentWord = this.words[this.wordIdx].split('')
this.displayText.push(this.currentWord.shift())
}
setTimeout(this.type, this.timeoutSpeed)
}
}
}
</script>
I need stop typing text, when element span is focused. How I can do it? I try do in method start:
!document.querySelector('#textCode').contains(document.activeElement)
But is not work.. I checked. Maybe is there another method to solve this problem? Please help me resolve this issue. Thanks.
i need use rotationAngle(vue2-leaflet-rotatedmarker) and duration(vue2-leaflet-movingmarker)
but i want use two props in single marker.
for example :
<l-marker :lat-lng="run.currentPoint.latLong"
:icon="run.currentPoint.icon" :rotationAngle="250" :duration="2000">
</l-marker>
thank you.
Vue2Leaflet Plugins are just wrappers around the original leaflet plugin. Therefore it's quite easy to combine the two wrappers
https://github.com/LouisMazel/vue2-leaflet-movingmarker/blob/master/lib/index.vue and
https://github.com/mudin/vue2-leaflet-rotatedmarker/blob/master/Vue2LeafletRotatedMarker.vue
of the two plugins into one. Call it e.g. LRotatedMovingMarker.vue, import it to your component and you can use it the way you wanted to.
<template>
<div style="display: none;">
<slot v-if="ready" />
</div>
</template>
<script>
import { marker, DomEvent, Icon } from 'leaflet'
import { findRealParent, propsBinder } from 'vue2-leaflet'
import 'leaflet.marker.slideto'
import 'leaflet-rotatedmarker'
const props = {
draggable: {
type: Boolean,
custom: true,
default: false
},
visible: {
type: Boolean,
custom: true,
default: true
},
latLng: {
type: [Object, Array],
custom: true
},
icon: {
custom: false,
default: () => new Icon.Default()
},
zIndexOffset: {
type: Number,
custom: false
},
rotationAngle:{
type: Number,
default: () => 0,
},
rotationOrigin: {
type: String,
default: 'center center'
},
options: {
type: Object,
default: () => ({})
},
duration: {
type: Number,
required: true
},
keepAtCenter: {
type: Boolean,
default: false
}
}
export default {
name: 'LRotatedMovingMarker',
props,
data() {
return {
ready: false
}
},
mounted() {
const options = this.options
if (this.icon) {
options.icon = this.icon
}
options.draggable = this.draggable
options.rotationAngle = this.rotationAngle?this.rotationAngle:0
options.rotationOrigin = this.rotationOrigin
this.mapObject = marker(this.latLng, options)
this.mapObject.on('move', ev => {
if (Array.isArray(this.latLng)) {
this.latLng[0] = ev.latlng.lat
this.latLng[1] = ev.latlng.lng
} else {
this.latLng.lat = ev.latlng.lat
this.latLng.lng = ev.latlng.lng
}
})
DomEvent.on(this.mapObject, this.$listeners)
propsBinder(this, this.mapObject, props)
this.ready = true
this.parentContainer = findRealParent(this.$parent)
this.parentContainer.addLayer(this, !this.visible)
},
beforeDestroy() {
this.parentContainer.removeLayer(this)
},
watch: {
rotationAngle: {
handler: function () {
this.options.rotationAngle = this.rotationAngle
}
}
},
methods: {
setDraggable(newVal) {
if (this.mapObject.dragging) {
newVal
? this.mapObject.dragging.enable()
: this.mapObject.dragging.disable()
}
},
setVisible(newVal, oldVal) {
if (newVal === oldVal) return
if (this.mapObject) {
if (newVal) {
this.parentContainer.addLayer(this)
} else {
this.parentContainer.removeLayer(this)
}
}
},
setLatLng(newVal) {
if (newVal == null) return
if (this.mapObject) {
const oldLatLng = this.mapObject.getLatLng()
const newLatLng = {
lat: newVal[0] || newVal.lat,
lng: newVal[1] || newVal.lng
}
if (
newLatLng.lat !== oldLatLng.lat ||
newLatLng.lng !== oldLatLng.lng
) {
this.mapObject.slideTo(newLatLng, {
duration: this.duration,
keepAtCenter: this.keepAtCenter
})
}
}
}
}
}
</script>
I created a component and a module for a functionality X and I'm using Vuex for state management. The code works for the every first time insertion, but after this the Getter function always returns the same value of the input before the action ends and commit the mutation.
For example:
1 - everything is [0,0,0] and Getter is [0,0,0]. Insert 9 in the first position and the value is inserted.
2 - On the second time, the check if the value inserted is equal of what is on the state returns true, so we had to remove this verification.
By the way, the state continues to be modified without the action commit the changes to mutation, and when we look to the Getter (who retrieves the value from the state) the value inserted is already returned by the Getter.
Someone know how to fix this?
Here is the code
component:
Vue.component('profundidade-cell', {
data: function () {
return {
valorProfundidade: [0, 0, 0],
id: this.face + '-' + this.dente,
ids: [
this.face + '-profundidade-sondagem-' + this.dente + '-1',
this.face + '-profundidade-sondagem-' + this.dente + '-2',
this.face + '-profundidade-sondagem-' + this.dente + '-3'
],
changedId: null,
valorInserido: null,
valorAnt: null,
}
},
props: {
arcada: String,
sextante: String,
dente: String,
face: String,
face_json: String,
max_length: Number,
min_value: Number,
max_value: Number,
},
computed: {
profundidadeSondagem() {
return store.getters['profundidadeSondagem/profundidadeSondagem']({arcada: this.arcada,
sextante: this.sextante, dente: "dente_" + this.dente, face: this.face_json});
},
presente() {
return store.getters.dentePresente({arcada: this.arcada, sextante: this.sextante,
dente: "dente_" + this.dente});
}
},
created: function() {
this.debouncedAlterarProfundidade = _.debounce(this.alterarValorProfundidadeSondagem, 400);
this.$root.$on("vuex-carregado", this.carregar);
},
methods: {
getValue(e) {
this.changedId = e.target.id;
this.valorInserido = e.target.value;
this.debouncedAlterarProfundidade();
},
alterarValorProfundidadeSondagem() {
let modelRefs = {};
let patologia = {
arcada: this.arcada,
sextante: this.sextante,
dente: "dente_" + this.dente,
face: this.face_json,
valor: this.valorProfundidade,
modelRefs: modelRefs,
id: this.changedId,
valorInserido: this.valorInserido,
};
store.dispatch('profundidadeSondagem/MODIFY', patologia).catch(() => {
this.valorProfundidade = this.profundidadeSondagem;
})
},
carregar(){
this.valorProfundidade = this.profundidadeSondagem;
}
},
template: `
<div>
<input type="text" :id=ids[0] v-on:input.prevent="getValue($event)" :maxlength=max_length v-model=valorProfundidade[0] class="periograma-input col l4" v-bind:class="{ 'invisible': !presente }" />
<input type="text" :id=ids[1] v-on:input.prevent="getValue($event)" :maxlength=max_length v-model=valorProfundidade[1] class="periograma-input col l4" v-bind:class="{ 'invisible': !presente }" />
<input type="text" :id=ids[2] v-on:input.prevent="getValue($event)" :maxlength=max_length v-model=valorProfundidade[2] class="periograma-input col l4" v-bind:class="{ 'invisible': !presente }" />
</div>
`
});
module:
const moduleProfundidadeSondagem = {
namespaced: true,
actions: {
MODIFY({commit, dispatch, getters, rootGetters}, obj) {
let patologia = {
face: rootGetters.getNomeFace(obj.face),
dente: rootGetters.getNomeDente(obj.dente),
local: "FACE",
ficha: this.state.idPeriograma,
descricao: obj.valor.toString(),
paciente: this.state.idPaciente,
tipo: 'PROFUNDIDADE_DE_SONDAGEM'
};
if(obj.valor) != getters.profundidadeSondagem(obj)) {
let reg = new RegExp(/([0-9],[0-9],[0-9])/);
let param = null;
return new Promise((resolve, reject) => {
if(obj.valor[0] == 0 && obj.valor[1] == 0 && obj.valor[2] == 0) {
param = axios.delete('/patologia', {data: patologia});
} else if (reg.test(obj.valor)){
param = axios.post('/patologia', patologia);
}
if(param != null) {
param.then(function (response) {
if(response.status == 200 || response.status == 201 && response.data) {
commit('armazenarProfundidadeSondagem', obj);
let dentes_data = {};
let face = '';
if (obj.arcada == 'arcada_superior' && obj.face == 'face_lingual_palatal') {
face = 'palatina'
} else {
face = obj.face.split('_')[1];
}
let classe_canvas = rootGetters.getNomeClasseCanvas(obj, face);
drawGraph(rootGetters.prepareDentesData(obj, face, dentes_data), face,
classe_canvas);
resolve();
}
}).catch(error => {
store.dispatch('mensagemAlerta/ALERTA', {
tipo: 'error',
mensagem: 'Não foi possível cadastrar o nível de sondagem'
});
reject(error);
});
}
})
}
},
RESET_PROFUNDIDADE_SONDAGEM({commit}, ob) {
commit('RESET_ALL', ob);
}
},
getters: {
profundidadeSondagem: (state, getters, rootState) => obj => {
return rootState[obj.arcada][obj.sextante][obj.dente][obj.face].profundidade_sondagem;
}
},
my guess is your issue lies here:
TL;DR - you pass your getter as valor to your action.
only a guess - as i cant debug your code
store.dispatch('profundidadeSondagem/MODIFY', patologia).catch(() => {
this.valorProfundidade = this.profundidadeSondagem;
})
as you assign a reference from your rootState[...] and thus you change the properties of the rootState[...] in your component past the first run.
So your code then behaves like:
let patologia = {
arcada: this.arcada,
sextante: this.sextante,
dente: "dente_" + this.dente,
face: this.face_json,
// valor: this.valorProfundidade,
///* same as */ valor: this.profundidadeSondagem,
/* same as */ valor: this.$store.getters['profundidadeSondagem/profundidadeSondagem'](...),
modelRefs: modelRefs,
id: this.changedId,
valorInserido: this.valorInserido,
};
A solution can be to this.valorProfundidade = this.profundidadeSondagem.slice(); as long it is an array or Object.assign({},...) - so you prevent the references