We have a dynamic component for tab
body, which defined as
<component :is="currentTab.itemType" :itemId="currentTab.itemId"></component>
Template has a span, which reflects itemId
- it changes every time when the currentTab
changed in tabs host component.
Each component of tab.itemType
has Vuex module, belongs to it specific type.
For example, there is store module product
with described state:
{
products: { [itemId: string]: IProduct }
}
When component created or itemId
changed, it tries to run load action and put loaded product to products
of vuex state.
So, there is Vue computed property, looks like
@State(productNamespace)
state: IProductState;
get currentProduct() {
return this.state.products[this.itemId];
}
or even
@Getter(GetterNames.GET_PRODUCT_BY_ID, bindingOptions)
getProductById: (itemId: string) => IProduct;
get currentProduct() {
return this.getProductById(this.itemId);
}
Each product has attributes
list, wich iterated by v-for
with :key
.
<v-list :key="itemId"><!-- itemId has no effect there -->
<v-list-item v-for="attribute in currentProduct.attributes" :key="attribute.id">
...
</v-list-item>
</v-list>
The problem is:
when we change itemId
, the attributes list displays all attributes from last added product and does not refresh it when switching to previous "tabs" with another itemId
but the same itemType
.
I've tried to set :key
of parent div
as itemId
but with no effect.
When I set :key
to <component>
, vuex state becomes broken.
Vue version is 2.6.10
UPDATE:
It does not work with simple property of product too:
{{ currentProduct.name }}
Summary:
There is the itemId
property in. And computed property wich depends on it. So computed property does not reflect changes when itemId
prop changed while Vuex collection does not changed.
Confirmed:
Computed property renews only when state.products collection changed. I've emulate this by run createProduct
action for each tab switching. Collection in vuex state accepts unwatched product stub and reflect changes to legal currentProduct
with given itemId
UPDATE 2: component with watcher. Still no way...
@Component
export default class Product extends Vue {
@Prop({ type: Object, required: true })
readonly tabItem: ITabItem;
@State(productNamespace)
state: IProductState;
itemId: string;
created() {
//...
this.initCurrentProduct();
}
// No changes until state.products was changed.
get currentProduct(): IProduct | {} {
if (!this.state) return {};
return this.state.products[this.itemId];
}
@Watch('tabItem')
onTabItemChanged()
{
DEBUG && console.log('Tab changed: keep moving!');
this.initCurrentProduct();
}
private async initCurrentProduct() {
const { isNew, itemId } = this.tabItem;
if (itemId === this.itemId)
return;
DEBUG && console.log('ItemId changed.');
this.itemId = itemId;
// ...
}
// ...
}
itemId
. So I think there isproducts
collection changed event raised. – Arsyncget currentProduct()
- why space? Is it in computed section? – Eggon