Ag-grid checkbox undo/redo - vue.js

I want to implement Undo/Redo functionality in Checkbox cell type using Ag-Grid.
<template>
<input type="checkbox" #click="checkedHandler($event)" :checked="params.value" />
</template>
<script>
export default {
name: 'CheckboxVue',
methods: {
checkedHandler(event) {
let checked = event.target.checked;
let colId = this.params.column.colId;
this.params.node.setDataValue(colId, checked);
}
},
}
</script>
and I set cellRenderer to 'CheckboxVue'.
<ag-grid-vue style="height: 100vh;" class="ag-theme-alpine"
:columnDefs="columnDefs"
#grid-ready="onGridReady"
:defaultColDef="defaultColDef"
:rowData="rowData"
:rowModelType="rowModelType"
#cell-value-changed="onCellValueChanged"
#row-value-changed="onRowValueChanged"
:enableRangeSelection="enableRangeSelection"
:enableFillHandle="enableFillHandle"
:undoRedoCellEditing="undoRedoCellEditing"
:undoRedoCellEditingLimit="undoRedoCellEditingLimit"
:enableCellChangeFlash="enableCellChangeFlash"
>
</ag-grid-vue>
export default {
name: 'App',
data() {
return {
columnDefs: null,
gridApi: null,
columnApi: null,
rowData: null,
defaultColDef: {
flex: 1,
minWidth: 150,
},
rowModelType: null,
enableRangeSelection: true,
enableFillHandle: true,
undoRedoCellEditing: true,
undoRedoCellEditingLimit: 100,
enableCellChangeFlash: true,
onGridReady: null
};
},
}
I can set it, checkbox emits onCellValueChanged event. But I can't undo/redo this value. It works with default text/number fields. I tried Hotkeys Ctrl+Z and programmatically way this.gridApi.undoCellEditing();

Related

How to dynamically insert text in Ckeditor5 for Vue 2

My application provides many selectable standard paragraphs which users can insert at any point. In a previous version insertion was simple: CKEDITOR.instances[editorId].insertHTML(text).
I'm trying to use v5 api with model.insertContent(text) but get error:
"vue.runtime.esm.js:3020 TypeError: t2.is is not a function
at bl.rp (converters.js:771:21)
at bl.fire (emittermixin.js:199:30)
at <computed> (observablemixin.js:262:16)
at VueComponent.testInsert (Test.vue:29:1)"
Here's the composition file. I have tried accessing the insertContent method from this.editor and from the apiReference returned from the #ready event;
<template>
<div>
<button #click="testInsert('abracadabra')">Insert literal content</button>
<ckeditor tag-name="textarea" :editor="editor" v-model="doc.HTML" #ready="editorReady" :config="editorConfig"></ckeditor>
</div>
</template>
<script>
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
export default {
name: 'testEditorInsert',
mounted() {
},
data() {
return {
doc: {ID: 0, HTML: "This is a sample text. Insert here? This is the remainder of the sample text"},
editor: ClassicEditor,
editorData: 'loading',
editorConfig: {
toolbar: [ 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote' ],
},
editorApi:null ,
}
},
methods: {
testInsert: function(text) {
console.log(this.editorApi, text);
//this.editor.model.insertContent(text);
this.editorApi.model.insertContent(text);
},
editorReady: function(editor) {
this.editorApi = editor;
}
},
}
</script>

Function inside watch option doesn't invoke on state change Vue

I'm using vuex and I have divided it into different modules. In one of them I have states and a watcher. watcher doesn't seem to work. here is my code inside page-two/index.js file
import pageTwoMutations from "./mutations.js";
import pageTwoActions from "./actions.js";
export default {
namespaced: true,
data() {
return {
hadCovid: null,
hadAntibodyTest: null,
antibodiesTestDate: null,
antibodiesNumber: null,
covidSicknessDate: null,
};
},
mutations: pageTwoMutations,
actions: pageTwoActions,
watch: {
hadCovid(value) {
console.log("fire");
if (value === "no" || value === "have_right_now") {
this.hadAntibodyTest = null;
}
},
},
};
Here is my store's folder structure
I need to update my state with v-model(other options don't work in my case) inside child component. so I pass name of the state property and module from parent. child component's code:
<template>
<div>
<label :for="name" class="mb-4 font-bold">
{{ label }}
</label>
<div v-for="elem in options" :key="elem.value" class="ml-4">
<input-field
:id="elem.value"
v-model="$store.state[module][property]" // !! state changes here
:name="name"
type="radio"
:value="elem.value"
:rules="rules"
/>
<label :for="elem.value" class="ml-4">{{ elem.label }}</label>
</div>
<ErrorMessage class="text-red-500 text-center" :name="name" />
</div>
</template>
<script>
import { ErrorMessage } from "vee-validate";
export default {
components: {
ErrorMessage,
},
props: ["label", "module", "property", "name", "rules", "options"]
</script>
parent element's code:
<radio-input
label="some label question"
name="had_covid"
rules="required"
module="pageTwo"
property="hadCovid"
:options="[
{ label: 'yes', value: 'yes' },
{ label: 'non', value: 'no' },
{ label: 'have right now', value: 'have_right_now' },
]"
/>
state update is working fine, but watcher function doesn't fire anyways.

How do I check the component type of values inside the $slots?

I'll provide a simple example that would demonstrate the problem I'm facing.
So I have a page that includes the following code:
<Slider>
<Slide>
<p>test 1</p>
</Slide>
<Slide> test 2 </Slide>
<div>test3</div>
</Slider>
The problem is within the mounted section of the Slider.
Inside Slider
<template>
<div class="h-48 w-full">
<slot></slot>
</div>
</template>
<script>
export default {
data: () => ({
slides: [],
}),
watch: {
slides() {
console.log(this.slides);
},
},
mounted() {
this.$slots.default().forEach((vNode) => {
console.log(vNode);
// this.slides.push(node.componentInstance)
});
},
};
</script>
How do I check if the vNode is an instance of the Slide component?
The console log return the following object:
{
"__v_isVNode": true,
"__v_skip": true,
"type": {
"__hmrId": "6e03689e",
"__file": "<route to project>/src/components/CarouselSlide.vue"
},
"props": null,
"key": null,
"ref": null,
"scopeId": null,
"slotScopeIds": null,
"children": {
"_": 1
},
"component": null,
"suspense": null,
"ssContent": null,
"ssFallback": null,
"dirs": null,
"transition": null,
"el": null,
"anchor": null,
"target": null,
"targetAnchor": null,
"staticCount": 0,
"shapeFlag": 36,
"patchFlag": 0,
"dynamicProps": null,
"dynamicChildren": null,
"appContext": null
}
Slide is just the following:
<template>
<div class="slide">
<slot></slot>
</div>
</template>
<script>
export default {};
</script>
Here is a demo: link
Similarly to React element objects represented by JSX, Vue vnode objects have type property that is a string for DOM elements, and a component for Vue components.
There should be a check:
if (vNode.type === Slide) ...

Change background of v-data-table row on event from child component

I have an expanding data table in my parent component and a child component inside the expanded row with a button. I would like to change the background color of the associated row when I click the button inside the child component. I'm not sure how to target the row to add the css class on event.
ScanGrid(parent):
<template>
<v-flex v-if="items.length === 0">
<ScanAdd #selectBatch="showScan" />
</v-flex>
<v-card v-else class="ma-5">
<v-card-text>
<v-layout align-center>
<v-data-table
:headers="headers"
:items="items"
item-key="StorageName"
show-expand
single-expand
:expanded="expanded"
hide-default-footer
#click:row="clickedRow"
>
<template
#isDeleted="deleteRow"
v-if="groupBy === 'barCode'"
v-slot:expanded-item="{ item }"
>
<td :colspan="12">
<ScanGridCode :item="item" />
</td>
</template>
<template v-else v-slot:expanded-item="{ item }">
<td :colspan="12">
<ScanGridDef :item="item" />
</td>
</template>
</v-data-table>
</v-layout>
</v-card-text>
</v-card>
</template>
<script>
import { API } from "#/api";
import ScanAdd from "./ScanAdd";
import ScanGridCode from "./ScanGridCode";
import ScanGridDef from "./ScanGridDef";
export default {
name: "ScanGrid",
props: {
items: {
type: Array,
required: true
}
},
components: {
ScanGridCode,
ScanGridDef,
ScanAdd
},
methods: {
deleteRow(value) {
this.isDeleted = value;
},
showScan(value) {
this.selectedId = value;
this.addScanBatch(value);
this.$emit("processingBatch", true);
this.processingBatch = true;
},
async addScanBatch(Id) {
const selectedItems = await API.getPhysicalInventoryBatch(Id);
if (selectedItems.data.Id === this.selectedId) {
this.items = selectedItems.data.Locations;
}
},
clickedRow(value) {
if (
this.expanded.length &&
this.expanded[0].StorageName == value.StorageName
) {
this.expanded = [];
} else {
this.expanded = [];
this.expanded.push(value);
}
}
},
data: () => ({
isDeleted: false,
groupBy: "barCode",
expanded: [],
items: [],
toDelete: "",
totalResults: 0,
loading: true,
headers: [
{
text: "Localisation",
sortable: true,
value: "StorageName",
class: "large-column font-weight"
},
{
text: "Paquets scannés",
sortable: true,
value: "ScannedProduct",
class: "large-column font-weight"
},
{
text: "Paquets entrants",
sortable: true,
value: "Incoming",
class: "large-column font-weight"
},
{
text: "Paquets sortants",
sortable: true,
value: "Outgoing",
class: "large-column font-weight"
},
{
text: "Paquets inconnus",
sortable: true,
value: "Unknown",
class: "large-column font-weight"
}
]
})
};
</script>
ScanGridCode(child):
<template>
<div class="codeContainer">
<div class="cancelLocation">
<v-flex class="justify-center">
<v-btn class="ma-5" large color="lowerCase" tile #click="deleteLocation"
>Annuler le dépôt de cette localisation</v-btn
>
</v-flex>
</div>
</div>
</template>
<script>
export default {
name: "ScanGridCode",
props: {
item: {
type: Object,
required: true
}
},
methods: {
deleteLocation() {
this.item.IsDeleted = true;
this.$emit("IsDeleted", true);
}
},
data: () => ({
IsDeleted: false,
groupBy: 0,
headersGroupCode: [
{
text: "Code barre",
sortable: true,
value: "SerialNumber",
class: "large-column font-weight-light"
},
{
text: "De",
sortable: true,
value: "FromLocation",
class: "large-column font-weight-light"
},
{
text: "Vers",
sortable: true,
value: "ToLocation",
class: "large-column font-weight-light"
}
]
})
};
</script>
I use Vuetify 2.1.7 and Vue 2.6.10. When I click on the button I call deleteLocation function. I assume I need to $emit a value to my parent but after that I don't know how to target the tr to change its style.
Since you're using Vuex, I would suggest using some variable such as store.state.selectedRow to keep track of whether or not a row has been selected (or in cases where there are more than one row, which row has been selected). Then you can have a computed property myProperty = this.$store.state.selectedRow in your Vue component which will automatically reflect the single source of truth, and your conditional class can be bound to this myProperty. This means you don't need to worry about emitting on events.
The approach to emitting the event is what should be done. So I am assuming you will emit from deleteLocation function.
Since you need a custom styling on rows you need to add the items slot and add your logic there
<template v-slot:item="{ item, select}">
<tr :class="key === coloredRow ? 'custom-highlight-row' : ''">
<td :colspan="12">
<ScanGridCode #changeColor="changeColor(key)" :item="item" />
</td>
//add this method to your script element
changeColor(idx) {
this.coloredRow = idx;
}

Vue.js - Select / dropdown selected item vm binding is not working (bootstrap-vue)

I'm trying to create a simple vue that binds the selected item from a select/dropdown to a property in the vm.
I haven't been able to find a clear and simple example of how this is down when using an options collection that is also in the view model.
<template>
<div>
<h1>Select box</h1>
<b-dropdown id="ddCommodity"
name="ddCommodity"
v-model="ddTestVm.ddTestSelectedOption"
text="Select Item"
variant="primary"
class="m-md-2" v-on:change="changeItem">
<b-dropdown-item disabled value="0">Select an Item</b-dropdown-item>
<b-dropdown-item v-for="option in ddTestVm.options":selected="option.value == 'LME/ST_TNI_ALL'":value="option.value">{{option.text}}</b-dropdown-item>
</b-dropdown> <span>Selected: {{ ddTestVm.ddTestSelectedOption }}</span>
</div>
</template>
<script>
export default {
components: {
},
data() {
return {
someOtherProperty: null,
ddTestVm: {
originalValue: [],
ddTestSelectedOption: "Value1",
disabled: false,
readonly: false,
visible: true,
color: "",
options: [
{
"value": "Value1",
"text": "Value1Text"
},
{
"value": "Value2",
"text": "Value2Text"
},
{
"value": "Value3",
"text": "Value3Text"
}
]
}
}
},
methods: {
changeItem: async function () {
//grab some remote data
try {
let response = await this.$http.get('https://www.example.com/api/' + this.ddTestVm.ddTestSelectedOption + '.json');
console.log(response.data);
this.someOtherProperty = response.data;
} catch (error) {
console.log(error)
}
}
},
watch: {
},
async created() {
}
}
</script>
<style>
</style>
Regardless of what i've tried i cannot get the selected value in the dropdown to change the ddTestSelectedOption property of the vm.
Could anyone assist on this issue?
Thanks.
b-dropdown in bootstrap-vue does not support v-model. As the documentation states:
Dropdowns are toggleable, contextual overlays for displaying lists of
links and actions in a dropdown menu format.
In other words, b-dropdown is essentially a UI component for displaying a menu or similar set of options.
I expect what you want is b-form-select.
That said, you could add a click handler to the options that sets the value.
<b-dropdown-item v-for="option in ddTestVm.options"
:key="option.value"
:value="option.value"
#click="ddTestVm.ddTestSelectedOption = option.value">
Here is a working example.
I thing you need b-form-select
<template>
<div>
<b-form-select v-model="selected" :options="options"></b-form-select>
<b-form-select v-model="selected" :options="options" size="sm" class="mt-3"></b-form-select>
<div class="mt-3">Selected: <strong>{{ selected }}</strong></div>
</div>
</template>
<script>
export default {
data() {
return {
selected: null,
options: [
{ value: null, text: 'Please select an option' },
{ value: 'a', text: 'This is First option' },
{ value: 'b', text: 'Selected Option' },
{ value: { C: '3PO' }, text: 'This is an option with object value' },
{ value: 'd', text: 'This one is disabled', disabled: true }
]
}
}
}
</script>
Only b-form-select can achieve the selected value behaviour.
Non-Selected Value Preview:
Selected Value Preview:
Sample Code:
<template>
<div>
<b-form-select v-model="selected" :options="options"></b-form-select>
</div>
</template>
<script>
export default {
data() {
return {
selected: null,
options: [
{ value: 1, text: 'Please select an option' },
{ value: 2, text: 'This is First option' },
{ value: 3, text: 'Selected Option' }
]
}
}
}
</script>
Wanted to leave a comment, but code example looks pale there :)
Yes, b-dropdown does not properly support Vue model, but it doesn't have to.
For those still interested in exactly dropdown (f.e. because it looks fancier), consider:
<b-dropdown :text="$i18n.locale" >
<b-dropdown-item v-for="(lang, i) in $i18n.availableLocales" :key="`Lang${i}`" :value="lang" v-on:click="$i18n.locale = lang;" >{{lang}}</b-dropdown-item>
</b-dropdown>
Slecifically v-on:click, which can handle the model value change for you.