Adding dynamic layouts messes up styling

Hi,

I am creating a component where I populate the dashboard layout panels dynamically using a javascript object.

This is how it looks like.



When I click new block I get a pop up to select the chart type as below


By selecting the chart type I update the following json (which i use to populate the charts)

[
      {
        type: "spline",
        title: "Chart Title",
        data: {
          id: "onespline",
          position: {
            row: "0",
            col: "0"
          },
          seriesData: [ { x: 'Jan'y: 46 }, { x: 'Feb'y: 27 }, { x: 'Mar'y: 26 } ],
          seriesData1: [ { x: 'Jan'y: 37 }, { x: 'Feb'y: 23 }, { x: 'Mar'y: 18 } ],
          seriesData2: [ { x: 'Jan'y: 38 }, { x: 'Feb'y: 17 }, { x: 'Mar'y: 26 } ],
          primaryXAxis: {
              valueType: 'Category',
              interval: 1,
              majorGridLines: { width: 0 }
          }
        }
      }
    ]


Json gets updated properly. But the newly added chart is un draggable and size is wrong. Following is the screen shot of the result.




Followings are my project files.

Package.json

{
  "name""dynamic_dash",
  "version""0.1.0",
  "private"true,
  "scripts": {
    "serve""vue-cli-service serve",
    "build""vue-cli-service build"
  },
  "dependencies": {
    "@syncfusion/ej2-base""^19.3.47",
    "@syncfusion/ej2-charts""^19.3.46",
    "@syncfusion/ej2-compression""^19.3.43",
    "@syncfusion/ej2-data""^19.3.47",
    "@syncfusion/ej2-file-utils""^19.3.43",
    "@syncfusion/ej2-layouts""^19.3.44",
    "@syncfusion/ej2-pdf-export""^19.3.43",
    "@syncfusion/ej2-svg-base""^19.3.45",
    "@syncfusion/ej2-vue-base""^19.3.47",
    "@syncfusion/ej2-vue-buttons""^19.3.44",
    "@syncfusion/ej2-vue-charts""^19.3.46",
    "@syncfusion/ej2-vue-dropdowns""^19.3.47",
    "@syncfusion/ej2-vue-layouts""^19.3.44",
    "@syncfusion/ej2-vue-navigations""^19.3.46",
    "@syncfusion/ej2-vue-popups""^19.3.47",
    "bootstrap-vue""^2.21.2",
    "core-js""^3.6.5",
    "vue""^2.6.11"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel""~4.5.0",
    "@vue/cli-service""~4.5.0",
    "node-sass""^4.12.0",
    "sass-loader""^8.0.2",
    "vue-template-compiler""^2.6.11"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}


Main.js

import Vue from 'vue'
import App from './App.vue'
import { BootstrapVueIconsPlugin } from 'bootstrap-vue'

import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

Vue.use(BootstrapVue)
Vue.use(IconsPlugin)
Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')


App.vue

<template>
  <div id="app">
    <DashboardLayout :charts="charts" v-on:addBlockModal="toggleBlockModal(true)"/>
    <add-block-modal :show="showAddBlockModal" v-on:hideTab="toggleBlockModal(false)" v-on:addBlock="pushNewBlock($event)" />
  </div>
</template>

<script>
import AddBlockModal from './components/shared/AddBlockModal.vue';
import DashboardLayout from "./components/DashboardLayout.vue";

export default {
  name: 'MainDashboardComponent',
  components: {
    AddBlockModal,
    DashboardLayout
  },
  data: function(){
    return {
      showAddBlockModal: false,
      charts: undefined
    }
  },
  created: function() {
    let updatedCharts = [
      {
        type: "spline",
        title: "Chart Title",
        data: {
          id: "onespline",
          position: {
            row: "0",
            col: "0"
          },
          seriesData: [ { x: 'Jan'y: 46 }, { x: 'Feb'y: 27 }, { x: 'Mar'y: 26 } ],
          seriesData1: [ { x: 'Jan'y: 37 }, { x: 'Feb'y: 23 }, { x: 'Mar'y: 18 } ],
          seriesData2: [ { x: 'Jan'y: 38 }, { x: 'Feb'y: 17 }, { x: 'Mar'y: 26 } ],
          primaryXAxis: {
              valueType: 'Category',
              interval: 1,
              majorGridLines: { width: 0 }
          }
        }
      }
    ]
    
    this.charts = updatedCharts;
  },
  methods: {
    toggleBlockModal: function(state) {
      this.showAddBlockModal = state;
    },
    pushNewBlock: function(chartType) {

      var chartId = Math.ceil(Math.random()*10000000) + chartType;  // Generate id for new chart
      
      var numberOfCharts = this.charts.length - 1;  // lenght of sections - add new block
      
      // Calculate the position data (row and col)
      var rowNum = Math.floor(numberOfCharts/2) * 3;
      var colNum = (numberOfCharts%2)*3;

      var newChart;

      if(chartType == 'pie') {
        newChart = {
          type: "pie",
          title: "",
          data: {
            id: chartId,
            position: {
              row: rowNum,
              col: colNum
            },
            seriesData: [
              { x: "TypeScript"y: 13text: "TS 13%" },
              { x: "React"y: 12.5text: "Reat 12.5%" },
              { x: "MVC"y: 12text: "MVC 12%" },
              { x: "Core"y: 12.5text: "Core 12.5%" },
              { x: "Vue"y: 10text: "Vue 10%" },
              { x: "Angular"y: 40text: "Angular 40%" }
            ],
            legendSettings: { visible: false },
            dataLabel: { visible: trueposition: "Inside"name: "value" },
            tooltip: {
                enable: true
            }
          }
        }
      } else if (chartType == 'bar') {
        newChart = {
          type: "spline",
          title: "By Job Level",
          data: {
            id: chartId,
            position: {
              row: rowNum,
              col: colNum
            },
            seriesData: [ { x: 'Jan'y: 46 }, { x: 'Feb'y: 27 }, { x: 'Mar'y: 26 } ],
            seriesData1: [ { x: 'Jan'y: 37 }, { x: 'Feb'y: 23 }, { x: 'Mar'y: 18 } ],
            seriesData2: [ { x: 'Jan'y: 38 }, { x: 'Feb'y: 17 }, { x: 'Mar'y: 26 } ],
            primaryXAxis: {
                valueType: 'Category',
                interval: 1,
                majorGridLines: { width: 0 }
            }
          }
        }
      }

      this.charts.splice(this.charts.length-10newChart);
    }
  }
}
</script>
<style lang="scss">
  @import "../node_modules/@syncfusion/ej2-base/styles/material.css";
  @import "../node_modules/@syncfusion/ej2-vue-buttons/styles/material.css";
  @import "../node_modules/@syncfusion/ej2-vue-popups/styles/material.css";
  @import "../node_modules/@syncfusion/ej2-vue-navigations/styles/material.css";

  .d-flex {
    displayflex;
    &.wrap {
      flex-wrapwrap;
    }
    &.justify {
      &-start{
        justify-contentflex-start;
      }
      &-around {
        justify-contentspace-around;
      }
      &-between {
        justify-contentspace-between;
      }
    }
    &.align-center {
      align-itemscenter;
    }
    .dropdown {
      width15%;
      margin-right10px;
    }
  }
  .kebab-menu {
    floatright;
  }
</style>


components/DashboardLayout.vue

<template>
    <div>
        <ejs-dashboardlayout id='dashboardlayoutid' :cellSpacing="cellSpacing ? cellSpacing : [2020]" :columns="6" v-if="charts[0].data">
            <div :style="display: chart.type=='newBlock' ? 'none' : '' }" v-for="(chartchartIndexin charts" :key="chartIndex" :id="'one'+chartIndex" class="e-panel" :data-row="(chart.data && chart.data.position) ? chart.data.position.row : 0" :data-col="(chart.data && chart.data.position) ? chart.data.position.col : 0" :data-sizeX="3" :data-sizeY="3">
                <div class="e-panel-container">
                    <div class="text-align" v-if="chart.type=='spline'">
                        <div>
                            <Spline />
                        </div>
                    </div>
                    <div class="text-align" v-if="chart.type=='pie'">
                        <div>
                            <Pie />
                        </div>
                    </div>
                </div>
            </div>
        </ejs-dashboardlayout>
        <div style="margin-top: 10px;">
            <div class="add-new-block d-flex justify-content-center align-items-center flex-column" v-on:click="addBlockModal()">
                <span class="add-icon-blue"></span>
                <p class="add-block-text">ADD BLOCK</p>
            </div>
        </div>
    </div>
</template>

<script>
    import Vue from "vue";
    import { DashboardLayoutPlugin } from "@syncfusion/ej2-vue-layouts";
    
    import Spline from "./charts/Spline.vue";
    import LineChart from "./charts/LineChart.vue";
    import Pie from "./charts/Pie.vue";

    Vue.use(DashboardLayoutPlugin);

    export default {
        components: {
            Spline,
            LineChart,
            Pie
        },
        props: {
            charts: {
                type: Array
            },
            newBlock: {
                type: Boolean
            },
            id: {
                type: String
            }
        },
        data: function() {
            return {
                cellSpacing: [2020],
                blockSize: 3
            };
        },
        methods: {
            addBlockModal() {
                this.$emit('addBlockModal');
            }
        }
    }
</script>

<style lang="scss" scoped>
@import "../../node_modules/@syncfusion/ej2-base/styles/material.css";
@import "../../node_modules/@syncfusion/ej2-vue-layouts/styles/material.css";
@import "../../node_modules/@syncfusion/ej2-inputs/styles/material.css";
@import "../../node_modules/@syncfusion/ej2-vue-dropdowns/styles/material.css";

.add-new-block {
    color#3FA8F5;
    backgroundrgba(631682450.1);
    border1px dashed;
    padding150px 120px;
    &:hover {
        cursorpointer;
    }
    .add-icon-blue {
        width40px;
        height40px;
        background-imageurl("../assets/images/add-icon-blue.png");
        background-repeatno-repeat;
    }
    .add-block-text {
        margin-top10px;
    }
}

.control-section {
    .d-flex {
        displayflex;
        &.justify-start {
            justify-contentflex-start;
        }
        &.align-center {
            align-itemscenter;
        }
        .dropdown {
            width15%;
            margin-right10px;
        }
    }
}

#dashboard_default .e-panel .e-panel-container .content {
  vertical-alignmiddle;
  font-weight600;
  font-size20px;
  text-aligncenter;
  line-height100px;
}

#dashboard_default .e-panel {
  transition:none !important;
}
</style>


components/charts/pie.vue

<template>
    <div id="container2" style='display:block;height:100%; width:100%;'>
      <ejs-accumulationchart class="chart-content" :legendSettings="legendSettings" :tooltip="tooltip" :width="chartWidth" :height="chartHeight">
        <e-accumulation-series-collection>
          <e-accumulation-series :dataSource='seriesData' xName='x' yName='y' innerRadius="40%" :dataLabel="dataLabel"> </e-accumulation-series>
        </e-accumulation-series-collection>
      </ejs-accumulationchart>
    </div>
</template>

<script>
import Vue from "vue";
import { AccumulationChartPluginPieSeriesAccumulationDataLabelAccumulationTooltipChartPluginfrom "@syncfusion/ej2-vue-charts";
import { ButtonPlugin } from "@syncfusion/ej2-vue-buttons";

Vue.use(ButtonPlugin);
Vue.use(ChartPlugin);
Vue.use(AccumulationChartPlugin);

export default {
    name: "Pie",
    data() {
        return {
            seriesData: [
                { x: "TypeScript"y: 13text: "TS 13%" },
                { x: "React"y: 12.5text: "Reat 12.5%" },
                { x: "MVC"y: 12text: "MVC 12%" },
                { x: "Core"y: 12.5text: "Core 12.5%" },
                { x: "Vue"y: 10text: "Vue 10%" },
                { x: "Angular"y: 40text: "Angular 40%" }
            ],
            legendSettings: { visible: false },
            dataLabel: { visible: trueposition: "Inside"name: "value" },
            tooltip: {
                enable: true
            },
            chartWidth: "99%",
            chartHeight: "99%"
        };
    },
    provide: {
        accumulationchart: [PieSeriesAccumulationDataLabelAccumulationTooltip]
    },
    mounted() {
        this.chartWidth = "100%";
        this.chartHeight = "100%";
    }
}
</script>


components/charts/Spline.vue

<template>
    <div id="container1" style='display:block;height:100%, width:100%;'>
    <!--  Chart element declaration -->      
        <ejs-chart class="chart-content" :primaryXAxis='primaryXAxis' :width="chartWidth" :height="chartHeight">
            <e-series-collection>
                <e-series :dataSource='seriesData' type='Column' xName='x' yName='y' name='Jan'> </e-series>
                <e-series :dataSource='seriesData1' type='Column' xName='x' yName='y' name='Feb' fill="rgb(239, 183, 202)"> </e-series>
                <e-series :dataSource='seriesData2' type='Column' xName='x' yName='y' name='Mar'> </e-series>
            </e-series-collection>
        </ejs-chart>
    <!-- end of chart element -->
    </div>
</template>
<script>
    import Vue from "vue";
    import { AccumulationChartPluginChartPluginColumnSeriesLegendCategory } from "@syncfusion/ej2-vue-charts";
    import { ButtonPlugin } from "@syncfusion/ej2-vue-buttons";

    Vue.use(ButtonPlugin);
    Vue.use(ChartPlugin);
    Vue.use(AccumulationChartPlugin);

    export default {
        name: "Spline",
        data: function() {
            return {
                seriesData: [ { x: 'Jan'y: 46 }, { x: 'Feb'y: 27 }, { x: 'Mar'y: 26 } ],
                seriesData1: [ { x: 'Jan'y: 37 }, { x: 'Feb'y: 23 }, { x: 'Mar'y: 18 } ],
                seriesData2: [ { x: 'Jan'y: 38 }, { x: 'Feb'y: 17 }, { x: 'Mar'y: 26 } ],
                primaryXAxis: {
                    valueType: 'Category',
                    interval: 1,
                    majorGridLines: { width: 0 }
                },
                chartWidth: "99%",
                chartHeight: "99%"
            };
        },
        provide: {
            chart: [ColumnSeriesCategoryLegend]
        },
        mounted() {
            this.chartWidth = "100%";
            this.chartHeight = "100%";
        }
    }
</script>
<style></style>


components/shared/AddBlockModal.vue

<template>
  <div class="addTabModal" :style="display: show ? '' : 'none' }">
       <div class="addTabModal__body">
            <div class="blockSelection d-flex justify-around align-center wrap">
                <div class="blockSelection__blockContainer" v-on:click="addBlock('pie'); hideTab();">
                    <div class="blockSelection__block blockSelection__block--pie">Pie chart</div>
                </div>
                <div class="blockSelection__blockContainer" v-on:click="addBlock('pie'); hideTab();">
                    <div class="blockSelection__block blockSelection__block--pie">Pie chart</div>
                </div>
                <div class="blockSelection__blockContainer" v-on:click="addBlock('pie'); hideTab();">
                    <div class="blockSelection__block blockSelection__block--pie">Pie chart</div>
                </div>

                <div class="blockSelection__blockContainer" v-on:click="addBlock('bar'); hideTab();">
                    <div class="blockSelection__block blockSelection__block--bar">bar chart</div>
                </div>
                <div class="blockSelection__blockContainer" v-on:click="addBlock('bar'); hideTab();">
                    <div class="blockSelection__block blockSelection__block--bar">bar chart</div>
                </div>
                <div class="blockSelection__blockContainer" v-on:click="addBlock('bar'); hideTab();">
                    <div class="blockSelection__block blockSelection__block--bar">bar chart</div>
                </div>
                
                <div class="blockSelection__blockContainer" v-on:click="addBlock('bar'); hideTab();">
                    <div class="blockSelection__block blockSelection__block--bar">bar chart</div>
                </div>
                <div class="blockSelection__blockContainer" v-on:click="addBlock('bar'); hideTab();">
                    <div class="blockSelection__block blockSelection__block--bar">bar chart</div>
                </div>
                <div class="blockSelection__blockContainer" v-on:click="addBlock('bar'); hideTab();">
                    <div class="blockSelection__block blockSelection__block--bar">bar chart</div>
                </div>
            </div>
           <div class="addTabModal__buttons">
            <button class="addTabModal__button addTabModal__button--cancel" v-on:click="hideTab">CANCEL</button>
            <button class="addTabModal__button addTabModal__button--add" v-on:click="addNewSection(); hideTab();">CREATE</button>
           </div>
       </div>
  </div>
</template>
<script>
    export default {
        name: "AddTabModal",
        props: {
            show: {
                type: Boolean,
                default: false
            }
        },
        methods: {
            hideTab: function() {
                this.$emit('hideTab');
            },
            addBlock: function(type) {
                this.$emit('addBlock'type);
            }
        }
    }
</script>
<style scoped lang="scss">
    .addTabModal {
        positionfixed;
        top0;
        left0;
        bottom0;
        right0;
        backgroundrgba(0,0,0,0.78);
        displayflex;
        align-itemscenter;
        justify-contentcenter;
        z-index2500;
        height100%;
        &__body {
            background#fff;
            padding32px;
            width800px;
        }
        &__title {
            font-weight700;
            size20px;
            line-height30px;
            color#626262;
        }
        &__description {
            font-weight400;
            font-size15px;
            line-height24px;
            color#626262;
        }
        &__label {
            font-weight600;
            font-size18px;
            line-height28px;
            color#707070;
            displayblock;
        }
        &__input {
            padding16px;
            width100%;
            color#626262;
            border1px solid;
            &:focus {
                outlinenone;
            }
        }
        &__buttons {
            displayflex;
            align-itemscenter;
            justify-contentflex-start;
            margin-top20px;
        }
        &__button {
            width160px;
            padding12px 0px;
            color#fff;
            font-weight600;
            font-size17px;
            bordernone;
            margin-right15px;
            &--cancel {
                background#4f4f4f;
            }
            &--add {
                background#3FA8F5;
            }
        }
    }
    .blockSelection {
        width100%;
        &__blockContainer {
            width30%;
            height120px;
            padding10px;
            background#F8F8F8;
            margin-bottom10px;
        }
        &__block {
            width100%;
            height100%;
            background-repeatno-repeat;
            background-sizecover;
        }

    }
</style>



1 Reply

SS Sharon Sanchez Selvaraj Syncfusion Team October 29, 2021 03:21 PM UTC

 
Greetings from Syncfusion support. 
 
Thank you for sharing the required code snippets along with a screenshot of your mentioned issue. We have tried incorporating the same in our sample, but we are facing few issues with package specifications. We have tried to create a similar scenario by modifying the chart data dynamically. 
 
Please refer to the sample: 
 
 
If suppose the panel content is not being fit properly on dynamically modifying the content data, please try by refreshing the content. 
 
Refer to the code snippet: 
 
this.$refs. .DashbordInstance.$el.querySelector(".chart-content").ej2_instances[0].refresh(); 
 
If the issue still persists, please confirm the following details. 
 
  1. Are you incorporating Dashboard Layout as a web component?
 
  1. Are you facing issues with panel content not being fit to the panel when modifying the content dynamically or even while dragging the panel?
 
  1. Can you please confirm with the above sample whether the following way is feasible in your environment(You can render data based on your requirement.
 
Please get back to us if you need any further assistance. 
 
Regards, 
Sharon Sanchez S. 


Loader.
Up arrow icon