How to align the width of the cells in the header and in the main part?
I marked the correct option in the picture with green checkmarks.
https://i.stack.imgur.com/PP1w2.png
My example and solution now: https://codepen.io/horus123/pen/YzVOGLQ
<div id="test">
<div class="table">
<div class="table__header">
<div v-for="(item,index) in headers" :key="index" class="table__head-el">
{{ item.title }}
</div>
</div>
<div class="table__body">
<div v-for="(el, indexx) in tableItems" :key="indexx" class="table__row">
<span v-for="(elem, indexxx) in el" :key="indexxx" class="table__field">
{{elem}}
</span>
</div>
</div>
</div>
One option would be to use the same grid for both the header and the main part. In other word the display: grid would be apply to the div.table element. In order to make div.table__head-el and div.table__field cells of this grid div.table__header, div.table__body and table__row must have display: contents. The rest of the CSS must be adapt as well but HTML and JS stay the same (I've added a blank property at the end of tableItems objects so the length of those items match the length of the header)
new Vue({
el: "#test",
data: {
headers: [
{
title: '#'
},
{
title: 'ID', icon: 'height'
},
{
title: 'Номер', icon: 'height'
},
{
title: 'Тип', icon: 'height'
},
{
title: 'Марка', icon: 'height'
},
{
title: 'Логист', icon: 'height'
},
{
title: 'Колонна', icon: 'height'
},
{
title: 'Трекер', icon: 'height'
},
{
title: 'Дата привязки трекера', icon: 'height'
},
{
title: 'Дата последних координат', icon: 'height'
},
{
title: 'Удалена'
},
{
title: 'Дата удаления'
}
],
tableItems: [
{
number: 1,
id: '42537370',
numberCar: 'В855АТ147',
type: 'Тягач',
brand: 'Mercedes-Benz',
logistician: 'Томсон Артём Александрович',
column: 'Андреев Евгений',
tracker: '86793',
dateStart: '29.03.2021 16:42:01',
dateEnd: '07.06.2021 13:49:39',
isDeleted: false,
blank: ''
},
{
number: 1,
id: '42537370',
numberCar: 'В855АТ147',
type: 'Тягач',
brand: 'Mercedes-Benz',
logistician: 'Имя Фамилия',
column: 'Андреев',
tracker: '48671111111193',
dateStart: '29.03.2021 16:42:01',
dateEnd: '07.06.2021 13:49:39',
isDeleted: false,
blank: ''
}
],
},
computed: {
},
methods: {
}
});
html {
--border: 1px solid black;
--border-radius: 8px;
}
.table {
max-width: 100%;
padding: 0 75px;
display: grid;
grid-template-columns: minmax(0, 60px) repeat(11, minmax(0, auto));
}
.table__header, .table__body, .table__row {
display: contents;
}
.table__head-el, .table__field {
padding: 12px 20px;
}
.table__head-el {
border-top: var(--border);
border-bottom: var(--border);
margin-bottom: 20px;
}
.table__head-el, .table__field {
display: grid;
place-items: center;
overflow: hidden;
}
.table__head-el:first-child {
border-left: var(--border);
border-radius: var(--border-radius) 0 0 var(--border-radius);
}
.table__head-el:last-child {
border-right: var(--border);
border-radius: 0 var(--border-radius) var(--border-radius) 0;
}
.table__row:first-child > .table__field {
border-top: var(--border);
}
.table__row:last-child > .table__field {
border-bottom: var(--border);
}
.table__field:first-child {
border-left: var(--border);
}
.table__field:last-child {
border-right: var(--border);
}
.table__row:first-child > .table__field:first-child {
border-top-left-radius: var(--border-radius);
}
.table__row:first-child > .table__field:last-child {
border-top-right-radius: var(--border-radius);
}
.table__row:last-child > .table__field:first-child {
border-bottom-left-radius: var(--border-radius);
}
.table__row:last-child > .table__field:last-child {
border-bottom-right-radius: var(--border-radius);
}
.table__row:hover > .table__field {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="test">
<div class="table">
<div class="table__header">
<div v-for="(item,index) in headers" :key="index" class="table__head-el">
{{ item.title }}
</div>
</div>
<div class="table__body">
<div v-for="(el, indexx) in tableItems" :key="indexx" class="table__row">
<span v-for="(elem, indexxx) in el" :key="indexxx" class="table__field">
{{elem}}
</span>
</div>
</div>
</div>
</div>
Related
I'm tryin to recreate this photo below and I am so close. I have run into a problem and I cannot seem to fix it. In my Snippet the text is not vertical aligned with the other container divs like they are in the photo. How can I align my text so the words are aligned? I have tried using flex box but because some text are longer/shorter then others they are all out of alignment because their positions are fixed.
const storeItems = [
{
name: 'TV',
price: 800.00,
inStock: true,
details: '4K Ultra HD'
},
{
name: 'Phone',
price: 700.00,
inStock: false,
details: '5G'
},
{
name: 'Game Console',
price: 300.00,
inStock: true,
details: 'The latest and greatest'
},
{
name: 'Laptop',
price: 1200.00,
inStock: true,
details: '16GB RAM 1TB SSD'
},
{
name: 'Smart Watch',
price: 200.00,
inStock: false,
details: 'Counts your steps'
},
{
name: 'Headphones',
price: 100.00,
inStock: true,
details: 'Clearest music to be heard'
},
{
name: 'Keyboard',
price: 100.00,
inStock: true,
details: 'Types for you'
},
{
name: 'HDMI Cord',
price: 100.00,
inStock: true,
details: 'HDMI to USB type C'
},
{
name: 'Monitor',
price: 300.00,
inStock: true,
details: '4K Ultra HD'
},
{
name: 'Speaker',
price: 200.00,
inStock: true,
details: 'Clearest music to be heard'
},
{
name: 'Video Game',
price: 60.00,
inStock: true,
details: 'Enjoy for hours'
},
];
storeItems.forEach(function(n, i, a) {
if (n.inStock == true) {
$('.boxes').append('<div class="container">' + '<p>$' + n.price +'</p>' + '<p>' + n.name + '</p>' + '<p>' + n.details + '</p>'
+
'</div>');
}
if (n.inStock == false) {
$('.boxes').append('<p class="notInStock">' + n.name + ': $' +
n.price + ' Not in stock' + '</p>');
}
})
$('#clickMe').appendTo('.boxes');
$('#clickMe').click(function(){
$('#contentContainer').toggleClass('darkModeBackground');
$('.container').toggleClass('darkModeContainers');
$(this).toggleClass('darkModeClickMe');
})
body {
font-family: Helvetica;
background-color: #d3d3d3;
color: black;
}
.shrink-container {
width: 800px;
height: 50px;
margin: 0 auto;
}
.container {
display: flex;
align-content: center;
justify-content: space-between;
align-items: center;
background-color: white;
padding: 0px 10px;
margin: 10px 0;
border-radius: 5px;
}
#clickMe {
display: inline-block;
padding: 10px;
font-family: Helvetica;
border-radius: 3px;
border: 1px solid;
}
#clickMe:hover{
cursor: pointer;
}
.inStock{
}
.notInStock{
display:none;
}
.darkModeBackground{
background-color: black;
color:white;
}
.darkModeContainers{
background-color: #5A5A5A;
color: white;
}
.darkModeClickMe{
border-color: white;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>List of items</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body id="contentContainer">
<div class="shrink-container">
<div id="header">
<h1>Products</h1>
<p>______
<p>
</div>
<div id="appendToMe">
<div class="boxes">
</div>
</div>
</div>
<div id="clickMe">Toggle Dark Mode</div>
<script src="https://code.jquery.com/jquery-3.5.0.slim.min.js" integrity="sha256-MlusDLJIP1GRgLrOflUQtshyP0TwT/RHXsI1wWGnQhs=" crossorigin="anonymous"></script>
<script src="app.js"></script>
</body>
</html>
A solution using <table>.
const storeItems = [
{
name: 'TV',
price: 800.00,
inStock: true,
details: '4K Ultra HD'
},
{
name: 'Phone',
price: 700.00,
inStock: false,
details: '5G'
},
{
name: 'Game Console',
price: 300.00,
inStock: true,
details: 'The latest and greatest'
},
{
name: 'Laptop',
price: 1200.00,
inStock: true,
details: '16GB RAM 1TB SSD'
},
{
name: 'Smart Watch',
price: 200.00,
inStock: false,
details: 'Counts your steps'
},
{
name: 'Headphones',
price: 100.00,
inStock: true,
details: 'Clearest music to be heard'
},
{
name: 'Keyboard',
price: 100.00,
inStock: true,
details: 'Types for you'
},
{
name: 'HDMI Cord',
price: 100.00,
inStock: true,
details: 'HDMI to USB type C'
},
{
name: 'Monitor',
price: 300.00,
inStock: true,
details: '4K Ultra HD'
},
{
name: 'Speaker',
price: 200.00,
inStock: true,
details: 'Clearest music to be heard'
},
{
name: 'Video Game',
price: 60.00,
inStock: true,
details: 'Enjoy for hours'
},
];
storeItems.forEach(function(n, i, a) {
$('#appendToMe').append('<tr><td>$' + n.price +'</td><td>' + n.name + '</td><td>' + n.details + '</td></tr>');
})
$('#clickMe').click(function(){
$('body').toggleClass('darkModeBackground');
$('#appendToMe').toggleClass('dark');
$(this).toggleClass('darkModeClickMe');
})
body {
font-family: Helvetica;
background-color: #d3d3d3;
color: black;
}
#appendToMe {
border-spacing: 0 .5em;
margin-bottom: 2em;
}
tr {
background-color: white;
}
td {
padding: 10px 20px;
}
td:first-child {
border-radius: 5px 0 0 5px;
}
td:last-child {
border-radius: 0 5px 5px 0;
}
#clickMe button {
padding: 10px;
font-family: Helvetica;
border-radius: 3px;
border: 1px solid;
}
.darkModeBackground {
background-color: black;
color:white;
}
#appendToMe.dark tr {
background-color: #5A5A5A;
color: white;
}
.darkModeClickMe {
border-color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<h1>Products</h1>
<table id="appendToMe"></table>
<div id="clickMe"><button>Toggle Dark Mode</button></div>
</body>
I'm trying to use a property of my data in a computed method like this:
data() {
return {
ToDoItems: [
{ id: uniqueId("todo-"), label: "Learn Vue", done: false },
{
id: uniqueId("todo-"),
label: "Create a Vue project with the CLI",
done: true,
},
{ id: uniqueId("todo-"), label: "Have fun", done: true },
{ id: uniqueId("todo-"), label: "Create a to-do list", done: false },
],
};
},
computed: {
listSummary() {
const numberFinishedItems = this.ToDoItems.filter((item) => item.done)
.length;
return `${numberFinishedItems} out of ${this.ToDoItems.length} items completed`;
},
},
But the IDE (Visual Studio Code) and the compiler throw an error:
Property 'ToDoItems' does not exist on type 'ComponentPublicInstance<{}, {}, {}, {}, {}, EmitsOptions, {}, {}, false, ComponentOptionsBase<{}, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, EmitsOptions, string, {}>>'.
I'm following the vue.js tutorial of mozilla (https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties#adding_a_summary_counter) but using v3.
Has anything changed that this isn't possible anymore / differently?
Thanks in advance
complete code:
<template>
<div id="app">
<h1>To-Do List</h1>
<to-do-form #todo-added="addToDo"></to-do-form>
<h2 id="list-summary">{{ listSummary }}</h2>
<ul aria-labelledby="list-summary" class="stack-large">
<li v-for="item in ToDoItems" :key="item.id">
<to-do-item :label="item.label" :done="true" :id="item.id"></to-do-item>
</li>
</ul>
</div>
</template>
<script lang="ts">
import uniqueId from "lodash.uniqueid";
import { defineComponent } from "vue";
import ToDoItem from "./components/ToDoItem.vue";
import ToDoForm from "./components/ToDoForm.vue";
export default defineComponent({
name: "App",
components: {
ToDoItem,
ToDoForm,
},
data() {
return {
ToDoItems: [
{ id: uniqueId("todo-"), label: "Learn Vue", done: false },
{
id: uniqueId("todo-"),
label: "Create a Vue project with the CLI",
done: true,
},
{ id: uniqueId("todo-"), label: "Have fun", done: true },
{ id: uniqueId("todo-"), label: "Create a to-do list", done: false },
],
};
},
methods: {
addToDo(toDoLabel: string) {
this.ToDoItems.push({
id: uniqueId("todo-"),
label: toDoLabel,
done: false,
});
},
},
computed: {
listSummary() {
const numberFinishedItems = this.ToDoItems.filter((item) => item.done)
.length;
return `${numberFinishedItems} out of ${this.ToDoItems.length} items completed`;
},
},
});
</script>
<style>
/* Global styles */
.btn {
padding: 0.8rem 1rem 0.7rem;
border: 0.2rem solid #4d4d4d;
cursor: pointer;
text-transform: capitalize;
}
.btn__danger {
color: #fff;
background-color: #ca3c3c;
border-color: #bd2130;
}
.btn__filter {
border-color: lightgrey;
}
.btn__danger:focus {
outline-color: #c82333;
}
.btn__primary {
color: #fff;
background-color: #000;
}
.btn-group {
display: flex;
justify-content: space-between;
}
.btn-group > * {
flex: 1 1 auto;
}
.btn-group > * + * {
margin-left: 0.8rem;
}
.label-wrapper {
margin: 0;
flex: 0 0 100%;
text-align: center;
}
[class*="__lg"] {
display: inline-block;
width: 100%;
font-size: 1.9rem;
}
[class*="__lg"]:not(:last-child) {
margin-bottom: 1rem;
}
#media screen and (min-width: 620px) {
[class*="__lg"] {
font-size: 2.4rem;
}
}
.visually-hidden {
position: absolute;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px);
clip: rect(1px, 1px, 1px, 1px);
clip-path: rect(1px, 1px, 1px, 1px);
white-space: nowrap;
}
[class*="stack"] > * {
margin-top: 0;
margin-bottom: 0;
}
.stack-small > * + * {
margin-top: 1.25rem;
}
.stack-large > * + * {
margin-top: 2.5rem;
}
#media screen and (min-width: 550px) {
.stack-small > * + * {
margin-top: 1.4rem;
}
.stack-large > * + * {
margin-top: 2.8rem;
}
}
/* End global styles */
#app {
background: #fff;
margin: 2rem 0 4rem 0;
padding: 1rem;
padding-top: 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 2.5rem 5rem 0 rgba(0, 0, 0, 0.1);
}
#media screen and (min-width: 550px) {
#app {
padding: 4rem;
}
}
#app > * {
max-width: 50rem;
margin-left: auto;
margin-right: auto;
}
#app > form {
max-width: 100%;
}
#app h1 {
display: block;
min-width: 100%;
width: 100%;
text-align: center;
margin: 0;
margin-bottom: 1rem;
}
</style>
Boussadjra Brahim's answer is "alright" but it doesn't actually address the issue. user16362509 is correct, but doesn't answer the question.. What you need to do is yes, annotate the return types of both your data properties and computed properties so TS knows what's going on. Not only that, but it provides stricter type checking if you annotate all types. I don't believe this issue actually occurs when properly using Vue3's composition API, but the problem does, as you can see, exist in options Api. Try: (Or consider using Composition Api). Weirdly enough, when you annotate the return type of a computed method, it understands the context, just quirks of Vue but it's good practice to have the types explicit.
<script lang="ts">
import uniqueId from "lodash.uniqueid";
import { defineComponent } from "vue";
import ToDoItem from "./components/ToDoItem.vue";
import ToDoForm from "./components/ToDoForm.vue";
export default defineComponent({
name: "App",
components: {
ToDoItem,
ToDoForm,
},
data(): { ToDoItems: Array<{id: *string*, label: string, done: boolean}> } {
return {
ToDoItems: [
{ id: uniqueId("todo-"), label: "Learn Vue", done: false },
{
id: uniqueId("todo-"),
label: "Create a Vue project with the CLI",
done: true,
},
{ id: uniqueId("todo-"), label: "Have fun", done: true },
{ id: uniqueId("todo-"), label: "Create a to-do list", done: false },
],
};
},
methods: {
addToDo(toDoLabel: string): void {
this.ToDoItems.push({
id: uniqueId("todo-"),
label: toDoLabel,
done: false,
});
},
},
computed: {
listSummary(): string {
const numberFinishedItems = this.ToDoItems.filter((item) => item.done)
.length;
return `${numberFinishedItems} out of ${this.ToDoItems.length} items completed`;
},
},
});
</script>
You are already using Vue 3. Why not use composition API with script setup for even better typescript support?
Live demo
<template>
<div id="app">
<h1>To-Do List</h1>
<form #submit.prevent="addToDo">
<input type="text" ref="label" />
<button type="submit">Add</button>
</form>
<h2 id="list-summary">{{ listSummary }}</h2>
<ul aria-labelledby="list-summary" class="stack-large">
<li v-for="item in ToDoItems" :key="item.id">
<input type="checkbox" v-model="item.done" />
{{ item.id }} {{ item.label }}
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
interface ToDoItem {
id: string;
label: string;
done: boolean;
}
const label = ref(null)
const ToDoItems = ref<ToDoItem[]>([
{ id: 1, label: 'Learn Vue', done: false },
{ id: 2, label: 'Create a Vue project with the CLI', done: true },
{ id: 3, label: 'Have fun', done: true },
{ id: 4, label: 'Create a to-do list', done: false },
]);
const addToDo = () => {
ToDoItems.value.push({
id: ToDoItems.value.length + 1,
label: label.value.value,
done: false,
});
label.value.value = '';
};
const listSummary = computed(() => {
return `${ToDoItems.value.filter((item) => item.done).length} out of ${ToDoItems.value.length} items completed`;
});
</script>
I have angular 8 application and I can show a popup.
But I want to style the popup. But how to do that?
SO I have this template:
<mgl-layer
*ngIf="imageLoaded"
id="camera"
type="symbol"
[source]="{
type: 'geojson',
data: {
type: 'FeatureCollection',
}
}"
(click)= "onClick($event)"
[layout]="{'icon-image': 'camera', 'icon-size': 0.25}"
>
</mgl-layer>
<mgl-popup *ngIf="selectedPoint" [feature]="selectedPoint">
<span [innerHTML]="selectedPoint.properties?.description"></span>
</mgl-popup>
and ts:
allWifiPoints = this.wifiPoints.map((wifi) => ({
type: 'Feature',
properties: {
description:
// eslint-disable-next-line max-len
},
geometry: {
type: 'Point',
coordinates: wifi,
},
}));
onClick(evt: MapLayerMouseEvent) {
this.selectedPoint = evt.features![0];
}
and css:
.mapboxgl-popup-content-wrapper {
width: 89px;
}
but nothing change. The popup stays white
see image.
So what I have to change?
Thank you
So in css: toggle-layer.component.scss
I have this:
:host ::ng-deep .mapboxgl-popup-content-wrapper {
width: 89px;
}
Should work:
:host ::ng-deep .mapboxgl-popup-content-wrapper {
width: 89px;
height: max-content;
border: 2px solid #BF0404;
background-color: rgba(243, 207, 207, 0.7);
border-radius: 18px;
margin-bottom: 3px;
}
I am building a Dashboard where you are able to add, delete, move and resize Panels within a grid using GridstackJS. I am filling these Panels with different things. In this Example I am using a Highchart. For saving and restoring the position and Size of the Panels I use the standard serialization of GridstackJS.
My problem now is to save and restore the Content inside the Panels.
Is there an elegant way to save the Content and apply it to the correct Panel when restoring?
JSFiddle
HTML
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gridstack#0.5.5/dist/gridstack.css" />
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/gridstack#0.5.5/dist/gridstack.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/gridstack#0.5.5/dist/jquery-ui.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/gridstack#0.5.5/dist/gridstack.jQueryUI.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<button id="save-grid" class="btn btn-primary">Save Grid</button>
<button id="load-grid" class="btn btn-primary">Load Grid</button>
<button id="delete-grid" class="btn btn-primary">Delete Grid</button>
<div class="row">
<div class="col-sm-12">
<div class="grid-stack ui-droppable">
<div class="dragbox grid-stack-item ui-draggable ui-resizable" data-gs-id="draggable">
<h2 class="dragbox-header">Chart 1</h2>
<div class="dragbox-content">
<div class="text-center"> Item 1</div>
</div>
</div>
<div class="dragbox grid-stack-item ui-draggable ui-resizable" data-gs-id="draggable">
<h2 class="dragbox-header">Chart 2</h2>
<div class="dragbox-content"></div>
</div>
<div class="dragbox grid-stack-item ui-draggable ui-resizable" data-gs-id="draggable" data-gs-width="4" data-gs-height="4">
<h2 class="dragbox-header" id="testChartHeader">Chart 3</h2>
<div class="text-center" id="testChart"></div>
</div>
</div>
</div>
</div>
CSS
.dragbox {
margin: 5px 2px 20px;
background: #fff;
position: absolute;
border: 1px solid #ddd;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
.dragbox-header {
margin: 0;
font-size: 12px;
padding: 5px;
background: #f0f0f0;
color: #000;
border-bottom: 1px solid #eee;
font-family: Verdana;
cursor: move;
position: relative;
}
.dragbox-content {
display: block;
background: #fff;
margin: 5px;
font-family: 'Lucida Grande', Verdana;
font-size: 0.8em;
line-height: 1.5em;
}
#testChart {
height: 200px;
}
.placeholder {
background: lightgray;
border: 1px dashed #ddd;
border-radius: 5px;
}
JavaScript
$(function() {
var options = {
draggable: {handle: '.dragbox-header', scroll: false, appendTo: 'body'},
placeholderClass: "placeholder",
acceptWidgets: true,
cellHeight: 60
};
$('.grid-stack').gridstack(options);
new function () {
this.serializedData = [
];
this.grid = $('.grid-stack').data('gridstack');
this.loadGrid = function () {
this.grid.removeAll();
var items = GridStackUI.Utils.sort(this.serializedData);
items.forEach(function (node, i) {
this.grid.addWidget($('<div class="grid-stack-item ui-draggable ui-resizable" data-gs-id="draggable"><div class="dragbox grid-stack-item-content ui-draggable-handle"><div class="dragbox-header">Chart ' + (i + 1) + '</div></div></div>'), node);
}, this);
return false;
}.bind(this);
this.saveGrid = function () {
this.serializedData = $('.grid-stack > .grid-stack-item').map(function (i, el) {
el = $(el);
var node = el.data('_gridstack_node');
return {
x: node.x,
y: node.y,
width: node.width,
height: node.height
};
}).toArray();
return false;
}.bind(this);
this.clearGrid = function () {
this.grid.removeAll();
return false;
}.bind(this);
$('#save-grid').click(this.saveGrid);
$('#load-grid').click(this.loadGrid);
$('#delete-grid').click(this.clearGrid);
};
});
var chart = Highcharts.chart('testChart', {
chart: {
animation: false,
type: 'bar'
},
plotOptions: {
series: {
animation: false,
}
},
title: {
text: 'Fruit Consumption'
},
xAxis: {
categories: ['Apples', 'Bananas', 'Oranges']
},
yAxis: {
title: {
text: 'Fruit eaten'
}
},
series: [{
name: 'Jane',
data: [1, 0, 4]
}, {
name: 'John',
data: [5, 7, 3]
}]
});
$('.grid-stack').on('change', function(event, items) {
var chartContainer = chart.renderTo;
$(chartContainer).css(
'height',
$(chartContainer.parentElement).height() - $('#testChartHeader').height()
);
chart.reflow();
});
You need to create a chart again in the loadGrid function:
this.loadGrid = function() {
this.grid.removeAll();
var items = GridStackUI.Utils.sort(this.serializedData);
items.forEach(function(node, i) {
this.grid.addWidget($('<div class="grid-stack-item ui-draggable ui-resizable" data-gs-id="draggable"><div class="dragbox grid-stack-item-content ui-draggable-handle"><div class="dragbox-header">Chart ' + (i + 1) + '</div>' + (i === 2 ? '<div id="testChart"></div>' : '') + '</div></div>'), node);
}, this);
chart = createChart();
return false;
}.bind(this);
Live demo: https://jsfiddle.net/BlackLabel/pjy8b950/
In Vue, what should I do when I want to click a component to add styles to this component and to clean up the additional styles that have been clicked on other tabbox components before? Thanks in advance!
Here is the code of the sub component
<template>
<div :class="tabStyle" :style="boxstyle" #click="tabClick(name)">
{{name}}
<div class="selected-icon" v-show="isSelected"></div> <!--selected styles-->
<div class="tick" v-show="isSelected"></div> <!--selected styles-->
</div>
</template>
<script>
export default {
name: "tabbox",
props: {
name: {
type: String,
default: ""
},
boxstyle: {
type: Object,
defalult: {}
}
},
data() {
return {
isSelected: false,
tabStyle: {
"selected-box": false,
"unselected-box": true
}
};
},
methods: {
tabClick(name) {
this.isSelected = true;
this.borderChange("selected-box","unselected-box")//style add
this.$emit("getTabName", name);
},
borderChange(first, second) {
this.tabStyle[first] = true;
this.tabStyle[second] = false;
}
}
};
</script>
<style lang="scss" scoped>
.tab-box {
display: inline-block;
position: relative;
text-align: center;
padding: 1%;
font-size: 1rem;
width: 20%;
}
.unselected-box {
border: solid 1px #b9a7a76b;
#extend .tab-box;
}
.selected-box {
border: solid 1px #5ddb14;
#extend .tab-box;
}
.selected-icon {
position: absolute;
right: 0;
bottom: 0;
width: 0;
height: 0;
border-color: #5ddb14 transparent;
border-width: 0 0 20px 25px;
border-style: solid;
}
.tick {
position: absolute;
right: 0;
bottom: 0;
color: #fff;
&::after {
content: "✓";
}
}
</style>
And This is the code of the parent component
<template>
<div class="select-tab" :style="tabStyle">
<Header></Header>
<div class="label-content" v-for="(item,index) in categories" :key="index">
<meaning-label :name="item.name"></meaning-label>
<div class="box-content">
<TabBox #getTabName="getTabName" :name="_item.name" :boxstyle="styles" v-for="(_item,_index) in item.categoryList" :key="_index">
</TabBox>
</div>
</div>
</div>
</template>
<script>
import TabBox from "#/components/FindMusic/SelectTab/TabBox";
import MeaningLabel from "#/components/FindMusic/SelectTab/MeaningLabel";
import Header from "#/components/FindMusic/SelectTab/Header";
export default {
components: {
TabBox,
MeaningLabel,
Header
},
methods: {},
data() {
return {
styles: {
width: ""
},
allStyles: {
width: "94%",
margin: "2px 1.5%"
},
_categories: {}
};
},
mounted() {
this.categories = this.$store.state.CategoriesInfo.categories;
},
props: {
tabStyle: {
type: Object,
default: {}
},
categories: {
type:Array,
default: []
}
},
methods: {
getTabName(name){
this.$emit('getTabName',name)
}
}
};
</script>
<style lang="scss" scoped>
.box-content {
display: inline-block;
vertical-align: top;
width: 75%;
font-size: 0;
}
.label-content {
margin-top: 10px;
}
</style>
Just keep the style on the tab i click right now and remove the style i has clicked before .
One possible solution is get boxstyle from a Vue method:
<template>
<div class="select-tab" :style="tabStyle">
<Header></Header>
<div class="label-content" v-for="(item,index) in categories" :key="index">
<meaning-label :name="item.name"></meaning-label>
<div class="box-content">
<TabBox #getTabName="getTabName" :name="_item.name" :boxstyle="getTableStyle(_item.name)" v-for="(_item,_index) in item.categoryList" :key="_index">
</TabBox>
</div>
</div>
</div>
</template>
<script>
import TabBox from "#/components/FindMusic/SelectTab/TabBox";
import MeaningLabel from "#/components/FindMusic/SelectTab/MeaningLabel";
import Header from "#/components/FindMusic/SelectTab/Header";
export default {
components: {
TabBox,
MeaningLabel,
Header
},
methods: {},
data() {
return {
styles: {
width: ""
},
allStyles: {
width: "94%",
margin: "2px 1.5%"
},
_categories: {},
activeTabName: ''
};
},
mounted() {
this.categories = this.$store.state.CategoriesInfo.categories;
// you might want to set default activeTabName here or in Vue's watch
},
props: {
tabStyle: {
type: Object,
default: {}
},
categories: {
type:Array,
default: []
}
},
methods: {
getTabName(name){
this.$emit('getTabName',name)
this.activeTabName = name
},
getTableStyle (name) {
if (name === this.activeTabName) {
return this.allStyles
}
return {}
}
}
};
</script>
<style lang="scss" scoped>
.box-content {
display: inline-block;
vertical-align: top;
width: 75%;
font-size: 0;
}
.label-content {
margin-top: 10px;
}
</style>