Having some trouble with a custom Vue component using Vue Carousel(https://ssense.github.io/vue-carousel/) to build a slide from a node list in the index file. Some of the carousel data is read in through a data.json file, but I want to create a new slide based on an object containing a node list. So I believe I need to us v-for and then iterate through that object creating a <slide></slide> for each instance in the node list.
The NodeList is made in the mounted() lifehook, but Im not sure how to tie it to the component, ALSO still very new to Vue and I didn't build out this templating system. Any help would be appreciated!
import { Carousel, Slide } from 'vue-carousel';
let articles={};
export default {
name: 'ProductCarousel',
props: {
dnode: Object,
value: Object
},
components: {
Carousel,
Slide
},
data() {
return {
carousel: this.dnode,
product: articles
}
},
mounted() {
var _self = this;
var rowName = ".js-ep--" + _self.carousel.anchor;
let e4pRow = document.querySelector(rowName);
var productRows;
if (e4pRow && !window.isEditMode) {
productRows = e4pRow.querySelectorAll(".product-grid");
if (productRows) {
for (var len = productRows.length, i = 0; i < len; i++) {
articles[i] = productRows[i].querySelectorAll("article");
//console.log(articles[i]);
}
//console.log(articles);
}
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<section :id="carousel.anchor" :class="carousel.classList" >
<h1 v-if="carousel.header" v-text="carousel.header" />
<h2 v-if="carousel.subheader" v-text="carousel.subheader"/>
<p v-if="carousel.paragraphText" v-text="carousel.paragraphText" />
<carousel
:navigationEnabled="carousel.navigation"
:paginationEnabled="carousel.pagination"
:navigationNextLabel="carousel.navigationNextIcon"
:navigationPrevLabel="carousel.navigationPrevIcon"
:navigationClickTargetSize="carousel.arrowClickSize"
:perPageCustom="[
[640, carousel.numSlidesSmall],
[1024, carousel.numSlidesMedium],
[1920, carousel.numSlidesLarge]]">
<slide></slide>
</carousel>
</section>
</template>
import { Carousel, Slide } from 'vue-carousel';
let articles={};
export default {
name: 'ProductCarousel',
props: {
dnode: Object,
value: Object
},
components: {
Carousel,
Slide
},
data() {
return {
carousel: this.dnode,
product: []
}
},
mounted() {
var _self = this;
var rowName = ".js-ep--" + _self.carousel.anchor;
let e4pRow = document.querySelector(rowName);
var productRows;
if (e4pRow && !window.isEditMode) {
productRows = e4pRow.querySelectorAll(".product-grid");
if (productRows) {
for (var len = productRows.length, i = 0; i < len; i++) {
articles[i] = productRows[i].querySelectorAll("article");
//console.log(articles[i]);
}
//console.log(articles);
this.product = articles; //loop through product in your template
}
}
}
}
Related
I am trying to develop a simple plugin for CKEditor 5. My ultimate goal is to have the plugin emit the following HTML:
<div class="icms_note">
<div class="span-6 module-note">
<p>User can edit here</p>
</div>
<div class="clear"></div>
</div>
I was having issues with the user editable area being in the wrong spot so I reduced the output to just this:
<div class="icms_note">
<p>User can edit here</p>
</div>
and the data model looks like this:
<icms_note>
<paragraph>User can edit here</paragraph>
</icms_note>
So I can get the data model created correctly and the HTML ends up in the editor the way I expect but I can't edit the text in the paragraph. I click on the text and the cursor just jumps out. I've tried looking at other examples and the tutorials but I can't seem to get it to work right. My plugin code is below. Any help would be appreciated.
note.js
import Plugin from "#ckeditor/ckeditor5-core/src/plugin";
import NoteEditing from "./noteediting";
import NoteUI from "./noteui";
export default class Note extends Plugin {
static get requires() {
return [ NoteEditing, NoteUI ];
}
static get pluginName() {
return "IcmsNote";
}
}
noteui.js
import Plugin from "#ckeditor/ckeditor5-core/src/plugin";
import { ButtonView } from "#ckeditor/ckeditor5-ui";
export default class NoteUI extends Plugin {
init() {
const editor = this.editor;
editor.ui.componentFactory.add( "icms_note", (locale) => {
const button = new ButtonView(locale);
button.set({
label: "Note",
withText: true,
tooltip: true
});
button.on( "execute", () => {
editor.execute("insertNote");
});
return button;
} );
}
}
noteediting.js
import Position from "#ckeditor/ckeditor5-engine/src/view/position";
import NoteCommand from "./notecommand";
export default class NoteEditing extends Plugin {
init() {
this._defineSchema();
this._defineConverters();
this.editor.commands.add("insertNote", new NoteCommand(this.editor));
}
_defineSchema() {
const schema = this.editor.model.schema;
schema.register( "icms_note", {
inheritAllFrom: "$text",
allowIn: [ "$root", "$container" ],
isInline: true
});
}
_defineConverters() {
const conversion = this.editor.conversion;
conversion.for( "downcast" ).elementToElement({
model: "icms_note",
view: ( modelElementValue, conversionApi ) => {
const { writer } = conversionApi;
const outerDivElement = writer.createEditableElement("div", {class: "icms_note"});
return outerDivElement;
}
});//<div><div class=\"span-6 module-note\"><p>Enter note</p></div><div class=\"clear\"></div></div>
conversion.for( "upcast" ).elementToElement({
view: {
name: "div",
attributes: {
classes: [ "icms_note" ]
}
},
model: {
key: "icms_note",
value: viewElement => {
const val = viewElement.getChildren()[0].getChildren()[0].data;
return val;
}
}
});
}
}
notecommand.js
import Command from "#ckeditor/ckeditor5-core/src/command";
export default class NoteCommand extends Command {
constructor(editor) {
super(editor);
}
execute() {
console.log("NoteCommand#execute");
const model = this.editor.model;
const selection = model.document.selection;
model.change( modelWriter => {
let position = selection.getFirstPosition();
const icmsNote = modelWriter.createElement("icms_note");
const paragraph = modelWriter.createElement("paragraph");
modelWriter.insert(paragraph, icmsNote);
modelWriter.insertText("User can edit here", paragraph);
let positionElementName = position.parent.name;
while (positionElementName != "$root" && positionElementName != "$container") {
position = model.createPositionAfter(position.parent);
positionElementName = position.parent.name;
}
model.insertContent(icmsNote, position, null, {
setSelection: "after"
});
});
}
}
What is sortable? Why I got problem with it
sortTheHeadersAndUpdateTheKey(evt) {
const headersTmp = this.headers;
const oldIndex = evt.oldIndex;
const newIndex = evt.newIndex;
if (newIndex >= headersTmp.length) {
let k = newIndex - headersTmp.length + 1;
while (k--) {
headersTmp.push(undefined);
}
}
headersTmp.splice(newIndex, 0, headersTmp.splice(oldIndex, 1)[0]);
this.table = headersTmp;
this.anIncreasingNumber += 1;
},
},
directives: {
'sortable-table': {
inserted: (el, binding) => {
el.querySelectorAll('th').forEach((draggableEl) => {
// Need a class watcher because sorting v-data-table rows asc/desc removes the sortHandle class
watchClass(draggableEl, 'sortHandle');
draggableEl.classList.add('sortHandle');
});
Sortable.create(el.querySelector('tr'), binding.value ? { ...binding.value, handle: '.sortHandle' } : {});
},
},
},
<v-data-table
:headers="showHeaders"
:page="page"
:pageCount="numberOfPages"
:options.sync="options"
:loading="loading"
:server-items-length="totalItems"
:items="items"
:items-per-page="15"
class="mainTable"
#dblclick:row="editItem"
v-sortable-table="{onEnd:sortTheHeadersAndUpdateTheKey}"
:key="anIncreasingNumber"
:footer-props="{
showFirstLastPage: true,
firstIcon: 'mdi-arrow-collapse-left',
lastIcon: 'mdi-arrow-collapse-right',
prevIcon: 'mdi-minus',
nextIcon: 'mdi-plus'
}"
>
I'm just try to do this Dragging columns in a Vuetify v-data-table
but have a mistake I did all what he say and still got a problem I've installed and import vuedraggable
maybe import is wrong ---> import 'vuedraggable'
How i pass result to data vue? I don't understand, how tide vue example and sortablejs.
Project use boostrap-vue
<div>
<b-table v-sortable="sortableOptions" striped hover :items="items"></b-table>
</div>
</template>
<script>
import Sortable from "sortablejs";
const createSortable = (el, options, vnode) => {
return Sortable.create(el, {
...options,
});
};
const sortable = {
name: "sortable",
bind(el, binding, vnode) {
const table = el;
table._sortable = createSortable(
table.querySelector("tbody"),
binding.value,
vnode
);
},
};
I stumbled upon such a task in one of my projects. I know that there are many similar solutions here on stackoverflow, but they didn't work in my case. The thing was that no one tells you need to provide Sortable-object with dataIdAttr property and set a proper attribute in children of sortable-dom-element. At least you need to do it working with bootstrap-vue table. That will help to resort rows backwards and reset vue-reactive-data according to changed drag indexes.
I hope that will be useful for someone.
<template>
<b-table
v-draggable-rows="{ data: items, orderColumn: '№' }"
:items="items"
>
<template #cell(Dragger)>
<IconDragHandle />
</template>
</b-table>
</template>
<script>
import IconDragHandle from '~/components/icons/table/IconDragHandle.vue';
export default {
components: {
IconDragHandle,
},
data() {
return {
items: [],
};
},
created() {
this.items = [...Array(8).keys()].map(x => ({
'Dragger': '',
'№': x + 1,
'Cell1': x + 1,
'Cell2': x + 1,
'Cell3': x + 1,
}));
},
};
</script>
import Vue from 'vue';
import Sortable from 'sortablejs';
Vue.directive('draggable-rows', {
bind(el, binding, vnode) {
const table = el;
table._sortable = createSortable(
table.querySelector('tbody'),
binding.value,
vnode
);
},
});
const createSortable = (el, options, vnode) => {
let order = [];
const data = options.data;
const orderColumn = options.orderColumn;
for (let i = 0; i < el.children.length; i++) {
el.children[i].setAttribute('sortable-id', i);
}
return Sortable.create(el, {
dataIdAttr: 'sortable-id', // default: data-id
animation: 150,
easing: 'cubic-bezier(0.25, 1, 0.5, 1)',
handle: '.custom-table-draggable-handle',
ghostClass: 'custom-draggable-rows-ghost',
chosenClass: 'custom-draggable-rows-chosen',
dragClass: 'custom-draggable-rows-drag',
onStart() {
order = [...this.toArray()];
},
onEnd(evt) {
this.sort(order);
data.splice(evt.newIndex, 0, ...data.splice(evt.oldIndex, 1));
if (!orderColumn) return;
data.forEach((o, i) => {
o[orderColumn] = i + 1;
});
},
});
};
Draggable Draggable.Vue Bootstrap-Vue SortableJS v-sortable Reorder
Consider the following Vue component:
<template>
<!-- Carousel -->
<div class="carousel-container">
<div ref="carousel" class="carousel">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
data() {
return {
items: this.$refs.carousel.querySelector('*')
}
},
computed: {
count: function () {
return this.items.length;
}
},
created () {
console.log(this.count);
}
}
</script>
The above does not work, and I think that is because I am attempting to reference refs in the data object.
I am trying to get the count of DOM elements within the .carousel element. How should I go about achieving this?
Update
After doing some further research, I have found that it is possible to achieve like so:
<script>
export default {
data() {
return {
items: []
}
},
computed: {
count: function () {
return this.items.length;
}
},
mounted () {
this.items = this.$refs.carousel.children;
console.log(this.count);
}
}
</script>
However, I am not confident that this is the best way to achieve this. I appreciate that 'best' is subjective, but is anyone aware of a 'better' way to achieve this?
I think a simpler, more straightforward way of counting the elements in tag would be more like this:
<script>
export default {
data() {
return {
count: 0
}
},
mounted () {
this.count = this.$refs.carousel.children.length;
console.log(this.count);
}
}
</script>
We can get all the elements inside the .carousel class using below
var matched = $(".carousel *");
var total elements = matched.length;
if you need only slot count, you can use below
var matched = $(".carousel slot");
var total elements = matched.length;
I am using Vue. And I created MultiAccordion component for my test case. I want to open slide by status[index] flag. But this component is not working. Why this is not working?
var MultiAccordion = {
data: function() {
return {
items: [
'cat',
'dog',
'bird',
],
status: [],
};
},
created: function() {
for (let i = 0; i < this.items.length; ++i) {
this.status.push(false);
}
},
methods: {
handleToggle: function(index) {
this.status[index] = !this.status[index];
},
},
template: `
<ul>
<li v-for="(val, index) in items">
<button #click="handleToggle(index)">toggle</button>
<div v-if="status[index]">
{{ val }}
</div>
</li>
</ul>
`,
};
Due to limitations in JavaScript, Vue can not detect changes to an array when you assign value by index, i.e. the following is not reactive:
this.status[index] = !this.status[index];
You either have to use Vue.set:
this.$set(this.status, index, !this.status[index])
Or use splice:
this.status.splice(index, 1, !this.status[index])