How can I make the Vue component's class binding bind onto the inner element instead of the root element?
Suppose I have a very simple component that looks like this
Vue.component("my-component", {
template: `
<p class="foo bar">
<span>Hi</span>
</p>
`,
});
If I use the component like this
<my-component class="baz boo"></my-component>
Final rendered HTML will look like this
<p class="foo bar baz boo">
<span>Hi</span>
</p>
However, I want to bind my class onto the <span>
tag instead of the root element.
This is the result I want
<p class="foo bar">
<span class="baz boo">Hi</span>
</p>
How can I achieve this?
1 answer
-
answered 2021-01-11 05:26
Renato Manalili
For me, you can pass it as props.
<my-component :className="baz booz" />
inside that component
<span :class="class-name"> Hi </span>
See also questions close to this topic
-
Proper way of object copy from one element to another in Vue.js
I am new to Vue.js (I mostly use PHP) and I am trying to creating simple view where user can add an object from one component and place it's copy into another component.
Main template
<template> <div class="left"> <TaskList :tasks="tasks" v-on:pinned-add-task="pinnedAddTask" /> </div> <div class="right"> <PinnedList :pinned="pinned" /> </div> </template>
TaskList
<template> <div class="task-list"> <div v-for="task in tasks" :key="task.id"> <TaskItem :task="task" v-on:pinned-add-task="$emit('pinned-add-task', task)" /> </div> </div> </template>
TaskItem
<template> <div> <p>{{task.name}}</p> <button v-on:click="$emit('pinned-add-task', task)">+</button> </div> </template>
And as far as I am aware object "task" is passed by reference and when I try to create an empty object or an array and insert "task" into that newly created object/array when I change original "task" it is also being changed inside that new object and I don't want that.
I am getting my data (tasks) from API that I have created and I am using pagination system so I want to be able to switch pages without losing it from the pinned page.
I created code which looks like this but I don't like it and I don't think that's a good way to do this:
pinnedAddTask(item) { let pQuantity = 1; // I use this value because I want to be able to pin one task multipletimes let left = this.pinned; let right = []; for (let task of this.pinned) { if(item.id == task.id) { pQuantity = task.quantity + 1; left = this.pinned.filter(eItem => eItem.id < item.id); right = this.pinned.filter(eItem => eItem.id > item.id); } } const clone = {...item, quantity: pQuantity}; this.pinned = [...left, clone, ...right]; }
Can anyone confirm or reject this?
-
How to rename files i upload with vue-fineuploader?
Im uploading 3 images with vue-FineUploader but i want can give them names like :
photo-1.jpg photo-2.jpg photo-3.jpg
The node js server i used :
/** * NodeJs Server-Side Example for Fine Uploader (traditional endpoints). * Maintained by Widen Enterprises. * * This example: * - handles non-CORS environments * - handles delete file requests assuming the method is DELETE * - Ensures the file size does not exceed the max * - Handles chunked upload requests * * Requirements: * - express (for handling requests) * - rimraf (for "rm -rf" support) * - multiparty (for parsing request payloads) * - mkdirp (for "mkdir -p" support) */ // Dependencies var express = require("express"), fs = require("fs"), rimraf = require("rimraf"), mkdirp = require("mkdirp"), multiparty = require('multiparty'), app = express(), cors = require('cors'), // paths/constants fileInputName = process.env.FILE_INPUT_NAME || "qqfile", publicDir = process.env.PUBLIC_DIR || __dirname + "/", nodeModulesDir = process.env.NODE_MODULES_DIR || "node_modules/", uploadedFilesPath = process.env.UPLOADED_FILES_DIR || "uploads/", chunkDirName = "chunks", port = process.env.SERVER_PORT || 3031, maxFileSize = process.env.MAX_FILE_SIZE || 0; // in bytes, 0 for unlimited app.listen(port); // enable CORs app.use(cors()); // routes app.use(express.static(publicDir)); app.use("/node_modules", express.static(nodeModulesDir)); app.post("/uploads", onUpload); app.delete("/uploads/:uuid", onDeleteFile); function onUpload(req, res) { var form = new multiparty.Form(); form.parse(req, function(err, fields, files) { var partIndex = fields.qqpartindex; // text/plain is required to ensure support for IE9 and older res.set("Content-Type", "text/plain"); if (partIndex == null) { onSimpleUpload(fields, files[fileInputName][0], res); } else { onChunkedUpload(fields, files[fileInputName][0], res); } }); } function onSimpleUpload(fields, file, res) { var uuid = fields.test, responseData = { success: false }; file.name = fields.qqfilename; if (isValid(file.size)) { moveUploadedFile(file, uuid, function() { responseData.success = true; res.send(responseData); }, function() { responseData.error = "Problem copying the file!"; res.send(responseData); }); } else { failWithTooBigFile(responseData, res); } } function onChunkedUpload(fields, file, res) { var size = parseInt(fields.qqtotalfilesize), uuid = fields.qquuid, index = fields.qqpartindex, totalParts = parseInt(fields.qqtotalparts), responseData = { success: false }; file.name = fields.qqfilename; if (isValid(size)) { storeChunk(file, uuid, index, totalParts, function() { if (index < totalParts - 1) { responseData.success = true; res.send(responseData); } else { combineChunks(file, uuid, function() { responseData.success = true; res.send(responseData); }, function() { responseData.error = "Problem conbining the chunks!"; res.send(responseData); }); } }, function(reset) { responseData.error = "Problem storing the chunk!"; res.send(responseData); }); } else { failWithTooBigFile(responseData, res); } } function failWithTooBigFile(responseData, res) { responseData.error = "Too big!"; responseData.preventRetry = true; res.send(responseData); } function onDeleteFile(req, res) { var uuid = req.params.uuid, dirToDelete = uploadedFilesPath + uuid; rimraf(dirToDelete, function(error) { if (error) { console.error("Problem deleting file! " + error); res.status(500); } res.send(); }); } function isValid(size) { return maxFileSize === 0 || size < maxFileSize; } function moveFile(destinationDir, sourceFile, destinationFile, success, failure) { mkdirp(destinationDir, function(error) { var sourceStream, destStream; if (error) { console.error("Problem creating directory " + destinationDir + ": " + error); failure(); } else { sourceStream = fs.createReadStream(sourceFile); destStream = fs.createWriteStream(destinationFile); sourceStream .on("error", function(error) { console.error("Problem copying file: " + error.stack); destStream.end(); failure(); }) .on("end", function(){ destStream.end(); success(); }) .pipe(destStream); } }); } function moveUploadedFile(file, uuid, success, failure) { var destinationDir = uploadedFilesPath + uuid + "/", fileDestination = destinationDir + file.name; moveFile(destinationDir, file.path, fileDestination, success, failure); } function storeChunk(file, uuid, index, numChunks, success, failure) { var destinationDir = uploadedFilesPath + uuid + "/" + chunkDirName + "/", chunkFilename = getChunkFilename(index, numChunks), fileDestination = destinationDir + chunkFilename; moveFile(destinationDir, file.path, fileDestination, success, failure); } function combineChunks(file, uuid, success, failure) { var chunksDir = uploadedFilesPath + uuid + "/" + chunkDirName + "/", destinationDir = uploadedFilesPath + uuid + "/", fileDestination = destinationDir + file.name; fs.readdir(chunksDir, function(err, fileNames) { var destFileStream; if (err) { console.error("Problem listing chunks! " + err); failure(); } else { fileNames.sort(); destFileStream = fs.createWriteStream(fileDestination, {flags: "a"}); appendToStream(destFileStream, chunksDir, fileNames, 0, function() { rimraf(chunksDir, function(rimrafError) { if (rimrafError) { console.log("Problem deleting chunks dir! " + rimrafError); } }); success(); }, failure); } }); } function appendToStream(destStream, srcDir, srcFilesnames, index, success, failure) { if (index < srcFilesnames.length) { fs.createReadStream(srcDir + srcFilesnames[index]) .on("end", function() { appendToStream(destStream, srcDir, srcFilesnames, index + 1, success, failure); }) .on("error", function(error) { console.error("Problem appending chunk! " + error); destStream.end(); failure(); }) .pipe(destStream, {end: false}); } else { destStream.end(); success(); } } function getChunkFilename(index, count) { var digits = new String(count).length, zeros = new Array(digits + 1).join("0"); return (zeros + index).slice(-digits); }
I read in the FineUploader docs :
Property Description canvas the to be converted to a file & then uploaded name the name to assign to the created file
But i dont know how where to make the changes ?
Thank you for the help
-
vuetify filter and sort v-data-table with a formatted date column
I have a v-data-table with a column that is in milliseconds thet I formatted with moment like this:
<td>{{ props.item.creationDate | moment("h:mm D.M.YYYY") }}
I want to use the default sorting and filtering of vuetify but it turns out that if I'm formatting the date for display the filtering is not working because it is filtering the data itself which is not formatted, and if I'm formatting the data itself, the sort is not working because it is trying to sort the string formatted date.. is there a way to use the default sort and filter with my case or I have to use custom-filter/custom-sort? -
How do you unit test globally registered Vue Components?
I have a repo where people usually use Vue.component as the way to write components, not even exporting them as an ES6 module (It was before SFC's were a thing). Is there any way to extract that Vue.component registration and unit test it, without refactoring it at first?
Just like this:
Vue.component('knife', () => {...});
I see that this wouldn't be the best solution because we WILL have namespace pollution over that Vue global instance, and at some part the unit test might become a huge instance because of that, but I just wanted to know if there's a way to do it.
Since we are going to unit test some of those components we could refactor them as a SFC, and the tests would guarantee that they still work.
If you're just going to say: "don't do this", please at least show more issues for not doing it. :)
-
Page Not Loading if Certain Data Doesn’t Exist in Vue App
I am building an admin dashboard for a VR training platform. It tracks the performance of users during their experience in VR. I am having some issues with the loading of the User Profile page. When the user has completed certain modes of the training, the page loads. If they haven’t, the entire User Profile page won’t load.
I don’t think it’s a v-if issue. It seems that when certain data isn’t available to load, the whole thing just stalls. The whole page is about 1300 lines of code, so I’m not sure where to even start. Any thoughts?
-
Cannot read property 'forEach' of undefined VueJS Firebase
I use the framework VueJS and the NoSQL Database Firebase. Here I want to display the products' data. And particulary the images of the products stored in the Cloud Firestore in Firebase.
This is the HTML code :
<div class="col-md-4"v-for="(product, index) in products" :key="index"> <div class="card product-item"> <carousel :perPage="1"> <slide v-for="(image, index) in product.images" :key="index"> <img :src="image" class="card-img-top" alt="..." width="250px"> </slide> </carousel> <div class="card-body"> <div class="d-flex justify-content-between"> <h5 class="card-title">{{ product.name }}</h5> <h5 class="card-prices">{{ product.price }} €</h5> </div> <button class="btn btn-primary mx-3 butn" > Add to cart </button> </div> </div> </div>
and the js script :
<script> import {db} from '../../firebase'; export default { name: "Productslist", props: { msg: String }, data(){ return { products: [], } }, firestore() { return { products: db.collection("products") } } }, }; </script> It displays the products data like the name and the price but not the images. I have a Cannot read property 'forEach' of undefined.
-
Vue.js | Aggregate data of siblings
I have a parent component that renders a grid of many cells. Each cell of the grid is a child component, which loads its own data as needed. But there is also a special child that should aggregate data from the other childs reactively.
It would be possible to declare a computed object of aggregates in the parent component, and send its data as props to the aggregate child. But how can the parent get the data of its childs to compute?
-
Vue.js Dynamically Mapping Data Between Parent and Child Component
I feel like I am about to go down a path of extreme inefficiency when trying to keep data correctly mapped between a Parent and Child component.
If I have a simple Child Vue element like below
common/InputText.vue
<template> <input v-bind:id="name" v-bind:value="value" v-on:input="changed($event, $event.target.value)"> </template> <script> props: ['name', 'value'], methods: { changed(event, value) { this.$emit('emitChanged', event, value); } } </script>
If I have a Parent Vue element like below, it is binding data to the Child elements. The problem is that it seems to be only binding from the Parent to the Child, the Parent data is not updating
Parent.vue
<input-text name="field01" v-bind:value="field01" @emitChanged="changed"></input-text> <input-text name="field02" v-bind:value="field02" @emitChanged="changed"></input-text> <script> import inputText from "./common/InputText.vue"; export default { data() { return() { field01: '', field02: '' } }, components: { input-text: inputText }, changed(event, newValue) { console.log(newValue); } } </script>
I am able to update the Parent data with whatever the data the Child returns by changing the
changed
method to the belowchanged(event, newValue) { console.log(newValue); if( event.target.id == 'field01' ) { this.field01 = newValue; } if( event.target.id == 'field02' ) { this.field02 = newValue; } }
This feels like a hack though and will become unmanageable should there be many input fields. What is the correct way to reupdate the Parent data?