Select checkbox and shows its related objects in Vue.js - vue.js

In my Vue.js project, I have two separate components are Country and States. I have merged them in one page. So now if I select one country it will display related states. How to do this?
<template>
<div>
<div style=margin-left:355px><country-index></country-index></div>
<div style=margin-left:710px><state-index></state-index></div>
</div>
</template>
<script>
import { ROAST_CONFIG } from '../../../config/config.js';
import CountryIndex from './components/country/Index';
import StateIndex from './components/state/Index';
import { listen } from '../../../util/history.js';
import axios from 'axios'
let baseUrl = ROAST_CONFIG.API_URL;
export default {
name: 'LocationsView',
layout: 'admin/layouts/default/defaultLayout',
middleware: 'auth',
components: {
'country-index' : CountryIndex,
'state-index' : StateIndex,
},
data() {
return { currentComponent:'','countryId':''}
},
methods: {
updateCurrentComponent(){
console.log(this.$route.name);
let vm = this;
let route = vm.$route;
if(this.$route.name == "Locations"){
this.currentComponent = "country-index";
}
}
},
mounted() {
let vm = this;
let route = this.$route;
window.addEventListener('popstate',this.updateCurrentComponent);
},
created() {
this.updateCurrentComponent();
}
}
Country Component
<template>
<div style="display:flex;height:100%">
<d-dotloader v-if="componentLoading" />
<div id="parent" class="list-manager" v-if="!componentLoading">
<div class="list-header">
<div class="bulk-action" :class="{'hide': showTop}" >
<div class="pull-left">
Countries
</div>
<!-- /pull-left -->
<div class="pull-right">
<d-button #click.native = "addCountry();"><i class="icon icon-sm"></i><span>New</span></i></d-button>
</div>
</div>
<!-- /bulk-action -->
<div class="bulk-action" :style ="{display:(showTop)?'block!important':'none!important'}" >
<div class="btn-toolbar">
<d-check field-class="check" v-model="selectAll" wrapper-class="field-check field-check-inline" label-position="right" label="" value="sel" #click.native = "toggleSelectAll();"/>
<d-button :is-loading="isLoading" #click.native = "deleteCountry();">Delete<i class="icon icon-sm" name="trash-2"></i></d-button>
<!-- <div class="pull-right mt5"><div class="green-bubble"></div>{{SelectedItems}}</div> -->
<d-button #click.native = "closeBulkToolBar();">close<i class="icon icon-sm" name="x"></i></d-button>
</div>
</div>
<!-- /bulk-action -->
</div>
<d-dotloader v-if="subListComponentLoading" />
<d-list-items :data="fetchData" #rowClick="changeCountryView" ref="itemsTable">
<d-list-cell column-class="list-item-check" :column-styles="{width: '40px'}" type="selectAll">
<template scope="row">
<div class="field-check field-check-inline" #click.stop="toggleSelect(row.rowIndex)" >
<input type="checkbox" class="check" :id="row.id" :value="row.id" :checked="row.selectAll">
<label></label>
</div>
<d-button #click.native = "editCountry(row.id);">Edit</d-button>
</template>
</d-list-cell>
<d-list-cell column-class="list-item-content">
<template scope="row">
<div class="list-item-content">
<div class="list-item-title">
<div class="pull-right">{{row.ISO_Code}}</div>
<div title="" class="pull-left">{{row.country_name}}</div>
</div>
<div class="list-item-meta">
<div class="pull-right">{{row.Default_Currency}} | {{row.Call_prefix}} </div>
<div class="pull-left">{{row.Zone}}</div>
</div>
<span class="list-item-status enabled"></span>
</div>
</template>
</d-list-cell >
</d-list-items>
</div>
</div>
</template>
<script>
import axios from 'axios'
import { ROAST_CONFIG } from '../../../../../config/config.js';
var baseUrl = ROAST_CONFIG.API_URL;
export default {
data () {
return {
SelectedItems:"",
isLoading:false,
show:true,
searchBy: '',
activeSearch: '',
showTop: false,
selectAll : false,
componentLoading:true,
subListComponentLoading:false,
showModal: false,
form :{
country_name: '',
isCountryEnabled: true,
}
}
},
methods: {
async fetchData ({search, page, filter, sort,rows}) {
let resData;
let vm = this;
axios.defaults.headers.common['Authorization'] = "Bearer "+localStorage.getItem('token');
const res = await axios.post(baseUrl+'/country/fetch',{search, page, filter, sort,rows})
.then((response) => {
if( (typeof(response) != 'undefined') && (typeof(response.data) != 'undefined') && (typeof(response.data.fetch) != 'undefined')){
return response.data.fetch;
}
});
return res;
},
toggleSelect(rowId){
if(typeof(this.$refs.itemsTable.rows[rowId]) != 'undefined'){
this.$refs.itemsTable.rows[rowId].selectAll = !this.$refs.itemsTable.rows[rowId].selectAll;
let data = this.$refs.itemsTable.rows;
let status = false;
let selectAllStatus = true;
let items = 0;
for(var i=0;i <= data.length;i++){
if((typeof(data[i])!= 'undefined')&&(data[i].selectAll)){
items++;
this.SelectedItems = items +" Selected Items";
status = true;
}
if((typeof(data[i])!= 'undefined')&&(!data[i].selectAll)){
selectAllStatus = false;
}
this.showTop = status
}
}
},
toggleSelectAll(){
this.selectAll = !this.selectAll;
let items = 0;
let data = this.$refs.itemsTable.rows;
let status = false;
let rowId = '1'
for(var i=0;i <= data.length;i++){
if((typeof(data[i])!= 'undefined')){
items++;
this.SelectedItems = items +" Selected Items";
status = this.selectAll;
data[i].selectAll = status;
}
}
this.showTop = status
},
closeBulkToolBar(){
this.SelectedItems = "";
this.showTop = false;
},
}
}
State Component
<template>
<div style="display:flex;height:100%">
<d-dotloader v-if="componentLoading" />
<div id="parent" class="list-manager" v-if="!componentLoading">
<div class="list-header">
<div class="bulk-action" :class="{'hide': showTop}" >
<div class="pull-left">
States
</div>
<!-- /pull-left -->
<div class="pull-right">
<d-button #click.native = "addState();"><i class="icon icon-sm"></i><span>New</span></i></d-button>
</div>
</div>
<!-- /bulk-action -->
<div class="bulk-action" :style ="{display:(showTop)?'block!important':'none!important'}" >
<div class="btn-toolbar">
<d-check field-class="check" v-model="selectAll" wrapper-class="field-check field-check-inline" label-position="right" label="" value="sel" #click.native = "toggleSelectAll();"/>
<d-button :is-loading="isLoading" #click.native = "deleteState();">Delete<i class="icon icon-sm" name="trash-2"></i></d-button>
<!-- <div class="pull-right mt5"><div class="green-bubble"></div>{{SelectedItems}}</div> -->
<d-button #click.native = "closeBulkToolBar();">close<i class="icon icon-sm" name="x"></i></d-button>
</div>
</div>
<!-- /bulk-action -->
</div>
<d-dotloader v-if="subListComponentLoading" />
<d-list-items :data="fetchData" #rowClick="changeStateView" ref="itemsTable">
<d-list-cell column-class="list-item-check" :column-styles="{width: '40px'}" type="selectAll">
<template scope="row">
<div class="field-check field-check-inline" #click.stop="toggleSelect(row.rowIndex)" >
<input type="checkbox" class="check" :id="row.id" :value="row.id" :checked="row.selectAll">
<label></label>
</div>
<d-button #click.native = "editState(row.id);">Edit</d-button>
</template>
</d-list-cell>
<d-list-cell column-class="list-item-content">
<template scope="row">
<div class="list-item-content">
<div class="list-item-title">
<div class="pull-right">{{row.ISO_Code}}</div>
<div title="" class="pull-left">{{row.state_name}}</div>
</div>
<div class="list-item-meta">
<div class="pull-left">{{row.country_name}} </div>
<div class="pull-right">{{row.Zone}}</div>
</div>
<span class="list-item-status enabled"></span>
</div>
</template>
</d-list-cell >
</d-list-items>
</div>
<state-add></state-add>
<state-edit></state-edit>
</div>
</template>
<script>
import axios from 'axios'
import { ROAST_CONFIG } from '../../../../../config/config.js';
var baseUrl = ROAST_CONFIG.API_URL;
export default {
data () {
return {
SelectedItems:"",
isLoading:false,
show:true,
searchBy: '',
activeSearch: '',
showTop: false,
selectAll : false,
componentLoading:true,
subListComponentLoading:false,
showModal: false,
form :{
country_name: '',
isCountryEnabled: true,
}
}
},
methods: {
async fetchData ({search, page, filter, sort,rows}) {
let resData;
let vm = this;
axios.defaults.headers.common['Authorization'] = "Bearer "+localStorage.getItem('token');
const res = await axios.post(baseUrl+'/state/fetch',{search, page, filter, sort,rows})
.then((response) => {
if( (typeof(response) != 'undefined') && (typeof(response.data) != 'undefined') && (typeof(response.data.fetch) != 'undefined')){
return response.data.fetch;
}
});
return res;
},
changeStateView(row){
if(typeof(this.$children[7]) != 'undefined'){
this.$parent.stateId = row.id;
this.viewComponent = "state-main";
this.$children[7].readState(this.$parent.stateId);
this.$router.push({name:"StatesView", params: {id:row.id}});
}
},
toggleSelect(rowId){
if(typeof(this.$refs.itemsTable.rows[rowId]) != 'undefined'){
this.$refs.itemsTable.rows[rowId].selectAll = !this.$refs.itemsTable.rows[rowId].selectAll;
let data = this.$refs.itemsTable.rows;
let status = false;
let selectAllStatus = true;
let items = 0;
for(var i=0;i <= data.length;i++){
if((typeof(data[i])!= 'undefined')&&(data[i].selectAll)){
items++;
this.SelectedItems = items +" Selected Items";
status = true;
}
if((typeof(data[i])!= 'undefined')&&(!data[i].selectAll)){
selectAllStatus = false;
}
this.showTop = status
}
}
},
toggleSelectAll(){
this.selectAll = !this.selectAll;
let items = 0;
let data = this.$refs.itemsTable.rows;
let status = false;
let rowId = '1'
for(var i=0;i <= data.length;i++){
if((typeof(data[i])!= 'undefined')){
items++;
this.SelectedItems = items +" Selected Items";
status = this.selectAll;
data[i].selectAll = status;
}
}
this.showTop = status
},
closeBulkToolBar(){
this.SelectedItems = "";
this.showTop = false;
},
}
}

Without your component codes it will be difficult to accuratly answer but I can give a try. To communicate between your two components that don't have parent/child relationship you can use an EventBus. You have several choices on how to set up your EventBus; you can pass your event through your Vue root instance using $root, or you can create a dedicated Vue component like in this example.
Considering that you already have binded the event countrySelected($event) on each of your country checkbox, you could achieve to display the related states using something like this:
./components/country/Index
The CountryIndex trigger an event while a country is selected
methods: {
countrySelected(event) {
let currentTarget = event.currentTarget
this.$root.$emit("display-states",currentTarget.countryId);
}
}
./components/state/Index
The stateIndex component listen to the event and display the related state
mounted() {
/**
* Event listener
*/
this.$root.$on("display-states", countryId => {
this.diplayStates(countryId);
});
},
methods: {
displayStates(countryId) {
//your method selecting the states to be diplayed
}

Related

vuejs event modifier search list process

I'm a vue js newbie, I perform a get operation with the value entered in the search input and if there is a result, I show it in "listShow", if there is no result, I return "listShow" false. no problem so far. only if the user chooses any of the incoming data, I send the "name" searchtext of the incoming data to the input. but if there is no result "listShow false" and click somewhere outside the input
I want to make "newDiv" true. so "inputOutClick" does the job, but when I click on any of the "search" data, "inputOutClick" does not allow this "selecteds()" function to fire.
And also, is my coding style correct, I'm getting too repetitive.
Is it ok to use search #keyup?
Does it make sense to use v-on:focusout?
const app = new Vue({
el: '#app',
data: {
searchText: '',
listShow: true,
newDiv:false,
searcList:[],
},
methods: {
inputOutClick() {
this.listShow = false
},
selecteds(list) {
this.listShow = false;
this.searchText = list.name;
},
async search() {
if (this.searchText !== '') {
const res = await this.callApi('get', 'search' + '?filter=' + this.searchText)
if (res.status === 200) {
this.searcList = this.getList;
if (res.data.length > 0) {
this.listShow = true;
} else {
this.listShow = false;
}
}
} else {
this.listShow = false;
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<div>
<input
type="text"
v-model="searchText"
#keyup="search"
v-on:focusout="inputOutClick"
/>
<div v-if="listShow" style="background:red">
<ul>
<li v-for="(list, index) in searcList">
<a #click="selecteds(list)">{{ list.name }}</a>
</li>
</ul>
</div>
<div v-if="newDiv">
<p>hello</p>
</div>
</div>
</div>
You can use #mousedown.prevent on the searchList entries (where the click handler is attached). This prevents the v-on:focusout event being fired, if a searchList entry is clicked.
<input
type="text"
v-model="searchText"
#keyup="search"
v-on:focusout="inputOutClick"
/>
<a
#click="selectEntry(entry)"
#mousedown.prevent
>
xxx
</a>
Use #mousedown instead of #click.
=> #click runs after #focusout.
=> #mousedown runs before #focusout.
If you do not want to run the focusout function on the input field when the list is clicked at all then you can use #mousedown.prevent="selecteds(list)".
See example below (click on "Full page" so the console.log doesn't block the list):
const app = new Vue({
el: '#app',
data: {
searchText: '',
listShow: true,
newDiv:false,
searcList:[],
list: {}
},
methods: {
inputOutClick() {
console.log("inputOutClick");
if (this.listShow == false) {
console.log("mousedown was fired first");
}
this.listShow = false
},
selecteds(list) {
console.log("selecteds");
this.listShow = false;
this.searchText = list.name;
},
async search() {
console.log("search");
this.listShow = true;
this.searcList = ['aeaeg', 'tdthtdht', 'srgsr'];
this.list.name = "TEST"
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<div>
<input
type="text"
v-model="searchText"
#keyup="search"
v-on:focusout="inputOutClick"
/>
<div v-if="listShow" style="background:red">
<ul>
<li v-for="(list, index) in searcList">
<a #mousedown="selecteds(list)">LIST TEXT</a>
</li>
</ul>
</div>
<div v-if="newDiv">
<p>hello</p>
</div>
</div>
</div>

How to use "this" in Vue 3

I'm working on a component in Vue3/TypeScript. I'm relatively new to Vue.
I'm dynamically creating a div. I want to be able to delete it when a user clicks on the "x" button. This is the "closeStatus" method.
In JavaScript I can pass this, but Vue hates it.
If anyone can help.
Thanks.
Here is the code:
<template>
<div>
<button #click="addStatus()" >Add Status</button>
<div id="slide" class="slide-modal">
<div class="clear-notifications" #click='clearAllNotifications()'>Clear all notifications</div>
<div class="status-div">
<div>11:00 Booking requested</div>
<div #click="closeStatus(this)"><img src="../assets/cross.svg" /></div>
</div>
<div class="status-div">
<div>11:30 Booking requested</div>
<div #click="closeStatus(this)"><img src="../assets/cross.svg" /></div>
</div>
</div>
</div>
</template>
<script lang="ts">
export default {
name: 'SlideModal',
methods: {
clearAllNotifications() {
const allNotifications = document.querySelectorAll(".status-div");
for(let x=0;x<allNotifications.length;x++) {
allNotifications[x].remove(); //removes all the child elements.
}
document.getElementById('slide').style.visibility='hidden'; //This should be Vue reactive.
},
addStatus() {
document.getElementById('slide').style.visibility='visible'; //This should be Vue reactive.
const statusMessage = "Another Message"
var div = document.createElement('div');
div.setAttribute('class', 'status-div');
div.innerHTML = '<div>' + statusMessage + '</div><div onclick="closeStatus(this)"><img src="/src/assets/cross.svg" /></div>'
document.getElementById('slide').appendChild(div);
},
closeStatus(elm: any) {
elm.parentNode.remove();
const allNotifications = document.querySelectorAll(".status-div");
if(allNotifications.length == 0 ) {
document.getElementById('slide').style.visibility='hidden'; //This should be Vue reactive.
}
}
}
}
</script>
Code is javascript DOM management stuff and far from Vue style.
Vue manages DOM with variables and that is what makes javascript frameworks awesome.
Let me first share the modified code.
<template>
<div>
<button #click="addStatus()" >Add Status</button>
<div id="slide" class="slide-modal" v-show="visibleSlide">
<div class="clear-notifications" #click='clearAllNotifications()'>Clear all notifications</div>
<div class="status-div">
<div>11:00 Booking requested</div>
<div #click="closeStatus(this)"><img src="../assets/cross.svg" /></div>
</div>
<div class="status-div">
<div>11:30 Booking requested</div>
<div #click="closeStatus(this)"><img src="../assets/cross.svg" /></div>
</div>
</div>
</div>
</template>
<script lang="ts">
export default {
name: 'SlideModal',
data() {
return {
visibleSlide: true
}
},
methods: {
clearAllNotifications() {
const allNotifications = document.querySelectorAll(".status-div");
for(let x = 0; x < allNotifications.length; x++) {
allNotifications[x].remove(); //removes all the child elements.
}
this.visibleSlide = false
},
addStatus() {
this.visibleSlide = true;
const statusMessage = "Another Message";
var div = document.createElement('div');
div.setAttribute('class', 'status-div');
div.innerHTML = '<div>' + statusMessage + '</div><div onclick="closeStatus(this)"><img src="/src/assets/cross.svg" /></div>'
document.getElementById('slide').appendChild(div);
},
closeStatus(elm: any) {
elm.parentNode.remove();
const allNotifications = document.querySelectorAll(".status-div");
if(allNotifications.length == 0 ) {
this.visibleSlide = false
}
}
}
}
</script>
I have just updated what is commented: "//This should be Vue reactive."
But it is still not benefiting from Vue framework.
Here is my whole idea of Vue code
<template>
<div>
<button #click="addStatus()" >Add Status</button>
<div id="slide" class="slide-modal" v-if="statuses.length">
<div class="clear-notifications" #click='clearAllNotifications()'>Clear all notifications</div>
<div v-for="status in statuses" :key="status.id" class="status-div">
<div>{{ status.text }}</div>
<div #click="closeStatus(status)"><img src="../assets/cross.svg" /></div>
</div>
</div>
</div>
</template>
<script lang="ts">
export default {
name: 'SlideModal',
data() {
return {
statuses: [
{
id: 1,
text: '11:00 Booking requested'
}, {
id: 2,
text: '11:30 Booking requested'
}
]
}
},
methods: {
clearAllNotifications() {
this.statuses = []
},
addStatus() {
const statusMessage = "Another Message";
this.statuses.push({
id: this.statuses.length + 1,
text: statusMessage
})
},
closeStatus(elm: any) {
const index = this.statuses.map((status) => status.id).indexOf(elm.id);
this.statuses.splice(index, 1);
}
}
}
</script>
As you can see, DOM elements are managed by variables and their operations instead of DOM management methods.
Hope this is helpful

How to make disabled button after click in Vuejs

I have a button on my website that gives bonuses to the user. Button have several conditions in 1 button:
<button class="btn btn--small btn--purple" :disabled="isDisabled" #click="takeBonus">Take</button>
<script>
......
computed: {
isDisabled() {
return this.heal_used === 1 || this.diff < 10;
this.$forceUpdate();
},
},
.......
</script
But when user click Take button, and if all success, button is still active this.$forceUpdate(); not working. And i need make when user click Take button, and if all success, make this button disabled.
My full Bonus.vue:
<template>
<div class="inner-page">
<div class="account" v-if="loaded && !$root.isMobile">
<div class="page-header">
</div>
<div class="form-panels hide-below-m">
<div class="col-7" style="margin-top: 5rem;margin-right: 3rem;">
<div class="faucet-component mx-5" rv-class-boost="data.boostIsOpen">
<img src="https://dota2.skins1.games/src/img/components/shine.png?v=8ce59643e70cb2f8550deb6a249b5f29" class="faucet-component__shine-bg">
<div class="faucet-component__content d-flex justify-content-between align-items-center flex-column w-100" style="
height: 15rem;">
<div class="faucet-component__available-amount-block round-circle p-2">
<div class="faucet-component__availabe-amount-coins d-flex justify-content-center align-items-center round-circle h-100" rv-currency="model:amount">Спасение</div>
</div>
<!-- rivets: unless model:cnt | eq 0 --><div class="faucet-component__remaining">
<span rv-t="">Left</span>:
<span>{{ bonus_num }}</span><br>
<span rv-t=""></span>
<span>{{ diff }}</span>
</div>
<!-- rivets: if model:cnt | eq 0 -->
<div class="faucet-component__buttons-container d-flex align-items-center w-75 justify-content-around">
<button class="btn btn--small btn--purple" :disabled="isDisabled" #click="takeBonus">Take</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
loaded: false,
bonus: {},
diff: {},
user: {},
bonus_num: 0,
heal_used: {}
}
},
mounted() {
this.$root.isLoading = true;
if (!this.$cookie.get('token')) {
this.$root.isLoading = false;
this.$router.go(-1);
}
this.domain = window.location.protocol + '//' + window.location.hostname;
setTimeout(() => {
this.getUser();
}, 100);
},
computed: {
isDisabled() {
return this.heal_used === 1 || this.diff < 10;
this.$forceUpdate();
},
},
methods: {
getUser() {
this.$root.axios.post('/user/getProfile')
.then(res => {
const data = res.data;
console.log(data.heal_used);
console.log(data.diff);
this.loaded = true;
this.user = data.user;
this.bets = data.bets;
this.bonus = data.bonus;
this.diff = data.diff;
this.heal_used = data.heal_used;
this.new_day = data.new_day;
this.bonus_num = data.bonus_num;
this.$root.isLoading = false;
})
.catch(err => {
this.$root.isLoading = false;
this.$router.go(-1);
})
},
takeBonus() {
this.$root.axios.post('/user/takeBonus', {
value: this.user.cashback
})
.then(res => {
const data = res.data;
if (data.type === 'success') {
console.log(data.heal_used);
this.bonus_num = data.bonus_num;
this.$root.user.balance = data.newBalance;
this.heal_used = data.heal_used;
this.$forceUpdate();
}
this.$root.showNotify(data.type, this.$t(`index.${data.message}`));
})
},
}
}
How i can make it, when user click Take button, and if all success, so that the Take button becomes disabled?
I'm sorry but your code has no indentation, so I just did that on jsfiddler so you know "How to make disabled button after click in Vuejs". You can have a look on : https://jsfiddle.net/o81yvn05/1/
<div id="app">
<button :disabled="isDisabled" #click="disableButton()">Please click here</button>
</div>
<script>
new Vue({
el: "#app",
data: {
isDisabled: false,
},
methods: {
disableButton() {
this.isDisabled = true
}
}
})
</script>

VUEX Filtered computed property does not update at state change

I am using vuex , and with getters Iam filtering a array of data in the store.
In a parent component I am fetching the array and send it to a child with props.
The child component resieve filtered array with getters and save it in computed property.
But when I make changes by calling actions, store is updated but filtered array stayed the same.
When I send to the child component original unfiltered array it's okey.
It the vue dev tool I see correct updated getters.
Some of the code is below.
STORE
const getDefaultState = () => {
return {
activities: [],
error: null,
isActivitiesLoading: false,
isActivityUpdating: false,
}
}
const mutations = {
[FETCHING_ACTIVITIES](state) {
state.isActivitiesLoading = true;
state.error = null;
},
[FETCHING_ACTIVITIES_SUCCESS](state, activities) {
state.error = null;
state.isActivitiesLoading = false;
state.activities = activities
},
[FETCHING_ACTIVITIES_ERROR](state, error) {
state.error = error;
state.isActivitiesLoading = false
},
[UPDATING_ACTIVITY](state) {
state.isActivityUpdating = true;
state.error = null;
},
[UPDATING_ACTIVITY_SUCCESS](state, activity) {
state.error = null;
state.isActivityUpdating = false;
const index = state.activities.findIndex(a => a.id === activity.id)
state.activities[index] = activity;
},
[UPDATING_ACTIVITY_ERROR](state, error) {
state.error = error;
state.isActivityUpdating = false
},
}
const actions = {
async fetchActivities({ commit }) {
commit(FETCHING_ACTIVITIES);
try {
const response = await ActivitiesApi.fetchActivities();
const activities = response.data.data;
commit(FETCHING_ACTIVITIES_SUCCESS, activities);
return response.data.data;
} catch (error) {
commit(FETCHING_ACTIVITIES_ERROR, error);
return null;
}
},
async updateActivity({ commit }, payload) {
commit(UPDATING_ACTIVITY);
try {
const response = await ActivitiesApi.updateActivity(payload);
const activity = response.data.data;
commit(UPDATING_ACTIVITY_SUCCESS, activity);
return response.data.data;
} catch (error) {
commit(UPDATING_ACTIVITY_ERROR, error);
return null;
}
},
};
const getters = {
getActivities(state) {
return state.activities;
},
getRunningActivities(state) {
let today = new Date();
const activities = state.activities;
const filteredActivities = activities.filter(function(activity) {
let activityDate = new Date(activity.start_date)
return activityDate <= today
});
return filteredActivities;
},
};
export default {
namespaced: true,
state: getDefaultState(),
getters,
actions,
mutations,
}
PARENT COMPONENT
<template>
<div class="container">
<h3>Running Activities</h3>
<ActivitiesComponent
:initialActivitiesFromStore="runningActivities"
/>
</div>
</template>
import ActivitiesComponent from "../components/Activities";
export default {
components: {
ActivitiesComponent
},
mounted() {
this.$store.dispatch('activities/fetchActivities').then(
() => {
if (this.hasError) {
console.log(this.error)
} else {
}
}
);
},
computed: {
activitiesFromStore() {
return this.$store.getters['activities/getActivities'];
},
runningActivities() {
return this.$store.getters['activities/getRunningActivities']
},
},
}
</script>
CHILD COMPONENT
<template>
<div class="container">
<div v-if="isActivitiesLoading" class="spinner-border spinner"></div>
<div class="row">
<div class="col">
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Activities</th>
<th scope="col">Period</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="(activity, activityId) in $v.activities.$each.$iter" :key="activityId">
<th scope="row">{{ parseInt(activityId) + 1 }}</th>
<td>
<input type="text" class="form-control" v-model="activity.name.$model">
<div class="alert alert-danger" v-if="!activity.name.required">Print Name</div>
<div v-if="activitiesFromStore[activityId].is_paused" class="alert alert-warning">
Activity is paused
</div>
</td>
<td>
<input type="text" class="form-control" v-model="activity.activity_period.$model">
<div class="alert alert-danger" v-if="!activity.activity_period.required">Print period</div>
<div class="alert alert-danger" v-if="!activity.activity_period.integer || !activity.activity_period.minValue">Period > 0</div>
</td>
<td class="d-flex border-0">
<button #click="activity.$model.is_paused = ! activity.$model.is_paused" class="btn btn-light mr-1" v-bind:class="{ active: !activity.$model.is_paused }">
<span v-if="activity.$model.is_paused">Убрать с паузы</span>
<span v-else>Make pause</span>
</button>
<button #click="updateActivity(activity.$model)" :disabled="
isActivityUpdating || !activitiesChanged(activityId) || !activity.name.required || !activity.activity_period.required || !activity.activity_period.integer || !activity.activity_period.minValue
" type="button" class="btn btn-success mr-1">
<span v-if="isActivityUpdating && activityActed.id == activity.$model.id" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Change
</button>
<button #click="deleteActivity(activity.$model)" type="button" class="btn btn-danger">
<span v-if="isActivityDeleting && activityActed.id == activity.$model.id" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Delete
</button>
</td>
</tr>
</tbody>
</table>
<div class="collapse" id="collapseExample">
<div class="form-group row">
<div class="col-4">
<label for="newPassword-input">Name</label>
<input v-model="activityToAdd.name" class="form-control">
<div v-if="$v.activityToAdd.period.$dirty && !$v.activityToAdd.name.required" class="alert alert-danger">Print name</div>
</div>
<div class="col-4">
<label for="newPassword-input">Period</label>
<input v-model="activityToAdd.period" class="form-control">
<div class="alert alert-danger" v-if="$v.activityToAdd.period.$dirty && !$v.activityToAdd.period.required">Print period</div>
<div class="alert alert-danger" v-if="(!$v.activityToAdd.period.integer || !$v.activityToAdd.period.minValue)">period > 0</div>
</div>
</div>
<button #click="addActivity" :disabled="!$v.activityToAdd.name.required || !$v.activityToAdd.period.required || !$v.activityToAdd.period.integer || !$v.activityToAdd.period.minValue" type="button" class="btn btn-primary">
<span v-if="isActivityAdding" class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
add
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import {required, minValue, integer} from "vuelidate/lib/validators"
export default {
props: ['initialActivitiesFromStore'],
data() {
return {
activityActed: null,
justEdited: false,
justAdded: false,
justDeleted: false,
activityToAdd:{
name: '',
period: '',
isPaused: ''
}
}
},
computed: {
activitiesFromStore() {
return this.initialActivitiesFromStore
},
activities() {
return JSON.parse(JSON.stringify(this.initialActivitiesFromStore));
},
},
methods: {
activitiesChanged(id) {
if(this.activitiesFromStore[id] && this.activities[id].name == this.activitiesFromStore[id].name && this.activities[id].activity_period == this.activitiesFromStore[id].activity_period && this.activities[id].is_paused == this.activitiesFromStore[id].is_paused)
return false;
else
return true
},
updateActivity(activity){
this.activityActed = activity;
this.$store.dispatch('activities/updateActivity', activity).then(
() => {
if (this.hasError) {
console.log(this.error)
} else {
this.justEdited = true;
// still the same
console.log(this.$store.getters['activities/getRunningActivities']);
}
}
);
},
},
validations: {
activities: {
$each: {
name: {
required,
},
activity_period: {
required,
integer,
minValue: minValue(0)
},
is_paused: {
required,
},
}
},
}
}
</script>
The problem was that I did not follow the vue specification about modification of an array. I used vm.items[indexOfItem] = newValue which is not reactive.

Polymer. It is possible to render element in {{}}?

In json i have metadata of field's type of control (textbox, textarea, combobox, email, date, address etc).
{
"Metadata":
"Fields":
[
{
"Fieldname": "id",
"Title": "Uniq id",
"ClientValueType":"int",
"ClientControltType":"textbox",
"ClientInputWidth":"9"
},
{
"Fieldname": "name_full",
"Title": "org full name",
"ClientValueType":"string",
"ClientControlType":"textarea",
"ClientInputWidth":"100"
},
{
"Fieldname": "name_full",
"Title": "org full name",
"ClientValueType":"string",
"ClientControlType":"textarea",
"ClientInputWidth":"100"
}
]
},"Data":[ {id:1, name_full:"org1"}, {id:2, name_full:"org2"}]
}
Let's this controls in different files for each edit type: textbox.html, textarea.html, combobox.html etc.
Textbox.html for example
<polymer-element name="text-box" noscript>
<template>
here is textbox
</template>
</polymer-element>
I need to dynamically import these elements to render dynamic edit form based on field.ClientControlType value
<polymer-element name="rawc-detail" attributes="data">
<template>
<div class="panel panel-default">
<div class="panel-body">
<form class="form-horizontal" role="form">
<template id="fields" repeat="{{val in fields}}">
<div class="form-group">
<label for="val.Name" class="col-sm-2 control-label">{{val.Title}}</label>
<div class="col-sm-10">{{val.element}}</div>
</div>
</template>
</form>
</div>
</div>
<style>
</style>
</template>
<script>
Polymer({
data:{},
ready: function() {
this.fields = [];
},
dataChanged: function(oldValue, newValue) {
this.bindNewData();
},
bindNewData: function() {
console.log(this.data);
var t = document.querySelector('rawc-detail::shadow #fields');
if (t)
{
var model = {
fields: []
};
for (var i=0; i<this.data.Metadata.Fields.length; i++)
{
var field = this.data.Metadata.Fields[i];
//console.log(field);
if (field.ClientControlType == "textbox")
{
var link = document.createElement('link');
link.href='http://localhost/testdatafile?shema=polymer_parts&name=textbox.html';
this.parentNode.appendChild(link);
//this.ownerDocument
// Polymer.import(['http://localhost/testdatafile?shema=polymer_parts&name=textbox.html'], function() {
var name = 'el-'+field.Fieldname;
console.log(name);
var textbox = document.createElement(name, 'rawc-textbox');
console.log(textbox);
//t.appendChild(textbox);
field.element = textbox;
model.fields.push(field);
// var tt = document.querySelector('rawc-detail::shadow '+name);
// console.log('tt=', tt);
// tt.description = 'a dynamic import';
// });
}
// console.log(field);
}
t.model = model;
}
}
});
is this possible?
detail.html
<polymer-element name="rawc-detail" attributes="data">
<template>
<apply-author-styles></apply-author-styles>
<h3 title="{{data.Metadata.DescOne}}" class="text-center">{{data.Metadata.TitleOne}}</h3>
<div class="panel panel-default">
<div class="panel-body">
<form class="form-horizontal" role="form">
<div id="forminner">
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="button" class="btn btn-primary" on-tap="ClickOk()">Ок</button>
<button type="button" class="btn btn-primary" on-tap="ClickCancel()">Отмена</button>
</div>
</div>
</form>
</div>
</div>
<style>
</style>
</template>
<script>
Polymer({
data:{},
ready: function() {
this.fields = [];
},
dataChanged: function(oldValue, newValue) {
this.bindNewData();
},
inarray: function(val, arr) {
for(var i=0; i<arr.length; i++)
if (arr[i] == val)
return true;
return false;
},
bindNewData: function() {
var t = document.querySelector('rawc-detail::shadow #forminner');
var elementUrls = [];
for (var i=0; i<this.data.Metadata.Fields.length; i++)
{
var field = this.data.Metadata.Fields[i];
var el = null;
var name = 'el-'+field.Fieldname;
if (field.ClientControlType === "textbox")
{
el = document.createElement('rawc-textbox');
el.id = name;
el.data = this.data.Content[0].Data[field.Fieldname];
url = 'http://localhost/testdatafile?shema=polymer_parts&name=textbox.html';
if (!this.inarray(url, elementUrls))
elementUrls.push(url);
}
var div=document.createElement('div');
div.className="form-group";
var label = document.createElement('label');
label.id = name;
label.className = "col-sm-2 control-label";
label.for = field.Name;
label.innerHTML = field.Title;
div.appendChild(label);
if (el != null)
div.appendChild(el);
t.appendChild(div);
}
for(var i=0; i<elementUrls.length; i++)
Polymer.import([elementUrls[i]]);
}
});
</script>
</polymer-element>
textbox.html
<polymer-element name="rawc-textbox" attributes="data">
<template id="textbox">
<input type="text" value="{{data}}">
<button on-click="{{clickme}}">go</button>
</template>
<script>
Polymer(
{
clickme:function(e,p,o){
console.log(this.data);
}
});
</script>
</polymer-element>