#27 Adding Security Models Using Vuex Actions And Mutations
Saturday, December 14, 2019
In this article we focus on adding the vuex actions and mutations that will allow us to add new security models to our store. We of course start by adding in the constants that we need in order to specify which action and mutation should be run as well as the required payload type. With those things in place we will create a couple of new fuctions, the first of which will help us add items to the store and the other will be used to sort those items. The last modification we will need to make is to update our security details view so that we invoke our new add actions when appropriate.
Parts
- Part 45: Adjusting Shares
- Part 44: Plan Percentages
- Part 43: Home Securities
- Part 42: Updating Plans
- Part 41: Plan Details View
- Part 40: Portfolio Getters
- Part 39: Portfolio Plan
- Part 38: Portfolio Category
- Part 37: Account Securities
- Part 36: Account Transfer
- Part 35: View Account Security
- Part 34: Updating Deposit
- Part 33: View Account Deposit
- Part 32: Display Account Details
- Part 31: Account Getters
- Part 30: Deposits And Securities
- Part 29: Add Accounts Details
- Part 28: Refactoring Accounts
- Part 27: Add Security Models
- Part 26: Edit Security Details
- Part 25: View Security Details
- Part 24: Navigating To Details
- Part 23: Getters Validation
- Part 22: Query Parameters
- Part 21: Tab Entries
- Part 20: Tab Header
- Part 19: List View
- Part 18: Vuex Getters
- Part 17: End Domain Model
- Part 16: Start Domain Model
- Part 15: Pop Routes
- Part 14: Push Routes
- Part 13: Removing Accounts
- Part 12: Vuex (Decorators)
- Part 11: Vuex (Accounts)
- Part 10: The App Bar (Settings)
- Part 9: Remove Consumer Rxjs
- Part 8: The App Bar (Back)
- Part 7: Structuring Our App
- Part 6: Animation Between Views
- Part 5: Navigation Fade
- Part 4: Navigation Requests
- Part 3: Fade Animations (cont.)
- Part 2: Fade Animations
- Part 1: Splash Screen
Code Snippets
store-constants.ts (1:29)
...
export const ACTION_ADD_SECURITY = "ACTION_ADD_SECURITY";
export const ACTION_ADD_SECURITY_CATEGORY = "ACTION_ADD_SECURITY_CATEGORY";
export const ACTION_ADD_SECURITY_MARKET = "ACTION_ADD_SECURITY_MARKET";
export const ACTION_ADD_SECURITY_SEGMENT = "ACTION_ADD_SECURITY_SEGMENT";
export const ACTION_ADD_SECURITY_TERRITORY = "ACTION_ADD_SECURITY_TERRITORY";
export const ACTION_ADD_SECURITY_TYPE = "ACTION_ADD_SECURITY_TYPE";
...
export const MUTATION_ADD_SECURITY = "MUTATION_ADD_SECURITY";
export const MUTATION_ADD_SECURITY_CATEGORY = "MUTATION_ADD_SECURITY_CATEGORY";
export const MUTATION_ADD_SECURITY_MARKET = "MUTATION_ADD_SECURITY_MARKET";
export const MUTATION_ADD_SECURITY_SEGMENT = "MUTATION_ADD_SECURITY_SEGMENT";
export const MUTATION_ADD_SECURITY_TERRITORY = "MUTATION_ADD_SECURITY_TERRITORY";
export const MUTATION_ADD_SECURITY_TYPE = "MUTATION_ADD_SECURITY_TYPE";
...
security-types.ts (2:14)
...
export type PayloadAddSecurity = SecurityModel;
export type PayloadAddSecurityCategory = SecurityCategoryModel;
export type PayloadAddSecurityMarket = SecurityMarketModel;
export type PayloadAddSecuritySegment = SecuritySegmentModel;
export type PayloadAddSecurityTerritory = SecurityTerritoryModel;
export type PayloadAddSecurityType = SecurityTypeModel;
...
functions.ts (2:46)
...
export function add<T extends IStateItem>(state: IState<T>, item: T, func: (item: T) => string) {
if (typeof item === "undefined") {
throw new Error(`Cannot add 'undefined' item to the store.`);
}
if (item === null) {
throw new Error(`Cannot add 'null' item to the store.`);
}
item.id = state.index;
state.items = sort([...state.items, item], func);
state.index += 1;
}
...
export function sort<T>(items: T[], func: (item: T) => string) {
return items.sort((a, b) => {
const aStr = func(a).toUpperCase();
const bStr = func(b).toUpperCase();
if (aStr < bStr) {
return -1;
}
if (aStr > bStr) {
return 1;
}
return 0;
});
}
...
security-descriptor.ts (7:07)
export abstract class SecurityDescriptor {
...
public set id(id: number) {
this._id = id;
}
...
constructor(private _id: number, ...) {}
...
}
security-module.ts (7:34)
...
import {
ACTION_ADD_SECURITY,
ACTION_ADD_SECURITY_CATEGORY,
ACTION_ADD_SECURITY_MARKET,
ACTION_ADD_SECURITY_SEGMENT,
ACTION_ADD_SECURITY_TERRITORY,
ACTION_ADD_SECURITY_TYPE,
...
MUTATION_ADD_SECURITY,
MUTATION_ADD_SECURITY_MARKET,
MUTATION_ADD_SECURITY_CATEGORY,
MUTATION_ADD_SECURITY_SEGMENT,
MUTATION_ADD_SECURITY_TERRITORY,
MUTATION_ADD_SECURITY_TYPE,
...
} from "@/store/store-constants";
import { add... sort, ... } from "@/store/functions";
...
import {
...
PayloadAddSecurity,
PayloadAddSecurityCategory,
PayloadAddSecurityMarket,
PayloadAddSecuritySegment,
PayloadAddSecurityTerritory,
PayloadAddSecurityType,
...
} from "@/store/security-types";
...
function formatSecurity(payload: PayloadAddSecurity | PayloadUpdateSecurity) {
payload.symbol = payload.symbol.toUpperCase();
}
function formatSecurityDescriptor(
payload:
| PayloadAddSecuritySegment
| PayloadAddSecurityTerritory
| PayloadAddSecurityType
| PayloadUpdateSecuritySegment
| PayloadAddSecurityTerritory
| PayloadUpdateSecurityType,
) {
payload.text = payload.text
.toLowerCase()
.split(" ")
.map((x) => `${x.charAt(0).toUpperCase()}${x.slice(1)}`)
.join(" ");
}
function formatSecurityMarket(payload: PayloadAddSecurityMarket | PayloadUpdateSecurityMarket) {
payload.text = payload.text.toUpperCase();
}
function hydrateSecurity(store: Store<IStoreState>, payload: PayloadAddSecurity | PayloadUpdateSecurity) {
const category = (store.getters as ISecurityGetters)[GETTER_SECURITY_CATEGORY](payload.categoryId);
const market = (store.getters as ISecurityGetters)[GETTER_SECURITY_MARKET](payload.marketId);
payload.setCategory(category);
payload.setMarket(market);
}
function hydrateSecurityCategory(
store: Store<IStoreState>,
payload: PayloadAddSecurityCategory | PayloadUpdateSecurityCategory,
) {
const segment = (store.getters as ISecurityGetters)[GETTER_SECURITY_SEGMENT](payload.segmentId);
const territory = (store.getters as ISecurityGetters)[GETTER_SECURITY_TERRITORY](payload.territoryId);
const type = (store.getters as ISecurityGetters)[GETTER_SECURITY_TYPE](payload.typeId);
payload.setSegment(segment);
payload.setSegment(territory);
payload.setType(type);
}
...
security-module.ts (15:43)
...
export const securitiesActions: StoreActionTree = {
[ACTION_ADD_SECURITY](this, { commit }, payload: PayloadAddSecurity) {
hydrateSecurity(this, payload);
formatSecurity(payload);
commit(MUTATION_ADD_SECURITY, payload);
},
[ACTION_ADD_SECURITY_CATEGORY](this, { commit }, payload: PayloadAddSecurityCategory) {
hydrateSecurityCategory(this, payload);
commit(MUTATION_ADD_SECURITY_CATEGORY, payload);
},
[ACTION_ADD_SECURITY_MARKET](this, { commit }, payload: PayloadAddSecurityMarket) {
formatSecurityMarket(payload);
commit(MUTATION_ADD_SECURITY_MARKET, payload);
},
[ACTION_ADD_SECURITY_SEGMENT](this, { commit }, payload: PayloadAddSecuritySegment) {
formatSecurityDescriptor
commit(MUTATION_ADD_SECURITY_SEGMENT, payload);
},
[ACTION_ADD_SECURITY_TERRITORY](this, { commit }, payload: PayloadAddSecurityTerritory) {
formatSecurityDescriptor
commit(MUTATION_ADD_SECURITY_TERRITORY, payload);
},
[ACTION_ADD_SECURITY_TYPE](this, { commit }, payload: PayloadAddSecurityType) {
formatSecurityDescriptor
commit(MUTATION_ADD_SECURITY_TYPE, payload);
},
[ACTION_UPDATE_SECURITY](this, { commit }, payload: PayloadUpdateSecurity) {
hydrateSecurity(this, payload);
formatSecurity(payload);
commit(MUTATION_UPDATE_SECURITY, payload);
},
[ACTION_UPDATE_SECURITY_CATEGORY](this, { commit }, payload: PayloadUpdateSecurityCategory) {
hydrateSecurityCategory(this, payload);
commit(MUTATION_UPDATE_SECURITY_CATEGORY, payload);
},
[ACTION_UPDATE_SECURITY_MARKET](this, { commit }, payload: PayloadUpdateSecurityMarket) {
formatSecurityMarket(payload);
commit(MUTATION_UPDATE_SECURITY_MARKET, payload);
},
[ACTION_UPDATE_SECURITY_SEGMENT](this, { commit }, payload: PayloadUpdateSecuritySegment) {
formatSecurityDescriptor
commit(MUTATION_UPDATE_SECURITY_SEGMENT, payload);
},
[ACTION_UPDATE_SECURITY_TERRITORY](this, { commit }, payload: PayloadUpdateSecurityTerritory) {
formatSecurityDescriptor
commit(MUTATION_UPDATE_SECURITY_TERRITORY, payload);
},
[ACTION_UPDATE_SECURITY_TYPE](this, { commit }, payload: PayloadUpdateSecurityType) {
formatSecurityDescriptor(payload);
commit(MUTATION_UPDATE_SECURITY_TYPE, payload);
},
};
...
Advertisement
security-module.ts (19:54)
...
export const securitiesGetters: StoreGetterTree = {
[GETTER_SECURITIES]: (state, getters: ISecurityGetters) => {
return state[STATE_SECURITIES].items.map((x) => getters[GETTER_SECURITY](x.id));
},
[GETTER_SECURITY]: (state, getters: ISecurityGetters) => {
return (id: number) => {
const security = findById(state[STATE_SECURITIES], id);
storeActionValidator
.begin()
.while(StoreActions.Getting)
.throwIf(security)
.isUndefined(undefinedMessage("security", id, state[STATE_SECURITIES].index));
const category = getters[GETTER_SECURITY_CATEGORY](security!.categoryId);
const market = getters[GETTER_SECURITY_MARKET](security!.marketId);
return security!.setCategory(category).setMarket(market);
};
},
[GETTER_SECURITY_CATEGORIES]: (state, getters: ISecurityGetters) => {
return state[STATE_SECURITY_CATEGORIES].items.map((x) => getters[GETTER_SECURITY_CATEGORY](x.id));
},
[GETTER_SECURITY_CATEGORY]: (state, getters: ISecurityGetters) => {
return (id: number) => {
const category = findById(state[STATE_SECURITY_CATEGORIES], id);
storeActionValidator
.begin()
.while(StoreActions.Getting)
.throwIf(category)
.isUndefined(undefinedMessage("category", id, state[STATE_SECURITY_CATEGORIES].index));
const segment = getters[GETTER_SECURITY_SEGMENT](category!.segmentId);
const territory = getters[GETTER_SECURITY_TERRITORY](category!.territoryId);
const type = getters[GETTER_SECURITY_TYPE](category!.typeId);
return category!
.setSegment(segment!)
.setTerritory(territory!)
.setType(type!);
};
},
[GETTER_SECURITY_MARKET]: (state) => {
return (id: number) => {
const market = findById(state[STATE_SECURITY_MARKETS], id);
storeActionValidator
.begin()
.while(StoreActions.Getting)
.throwIf(market)
.isUndefined(undefinedMessage("market", id, state[STATE_SECURITY_MARKETS].index));
return market;
};
},
[GETTER_SECURITY_MARKETS]: (state) => {
return findAll(state[STATE_SECURITY_MARKETS]);
},
[GETTER_SECURITY_SEGMENT]: (state) => {
return (id: number) => {
const segment = findById(state[STATE_SECURITY_SEGMENTS], id);
storeActionValidator
.begin()
.while(StoreActions.Getting)
.throwIf(segment)
.isUndefined(undefinedMessage("segment", id, state[STATE_SECURITY_SEGMENTS].index));
return segment;
};
},
[GETTER_SECURITY_SEGMENTS]: (state) => {
return findAll(state[STATE_SECURITY_SEGMENTS]);
},
[GETTER_SECURITY_TERRITORIES]: (state) => {
return findAll(state[STATE_SECURITY_TERRITORIES]);
},
[GETTER_SECURITY_TERRITORY]: (state) => {
return (id: number) => {
const territory = findById(state[STATE_SECURITY_TERRITORIES], id);
storeActionValidator
.begin()
.while(StoreActions.Getting)
.throwIf(territory)
.isUndefined(undefinedMessage("territory", id, state[STATE_SECURITY_TERRITORIES].index));
return territory;
};
},
[GETTER_SECURITY_TYPE]: (state) => {
return (id: number) => {
const type = findById(state[STATE_SECURITY_TYPES], id);
storeActionValidator
.begin()
.while(StoreActions.Getting)
.throwIf(type)
.isUndefined(undefinedMessage("type", id, state[STATE_SECURITY_TYPES].index));
return type;
};
},
[GETTER_SECURITY_TYPES]: (state) => {
return findAll(state[STATE_SECURITY_TYPES]);
},
};
...
security-module.ts (20:29)
...
export const securitiesMutations: StoreMutationTree = {
[MUTATION_ADD_SECURITY](state, payload: PayloadAddSecurity) {
add(state[STATE_SECURITIES], payload, (x) => x.symbol);
},
[MUTATION_ADD_SECURITY_CATEGORY](state, payload: PayloadAddSecurityCategory) {
add(state[STATE_SECURITY_CATEGORIES], payload, (x) => x.text);
},
[MUTATION_ADD_SECURITY_MARKET](state, payload: PayloadAddSecurityMarket) {
add(state[STATE_SECURITY_MARKETS], payload, (x) => x.text);
},
[MUTATION_ADD_SECURITY_SEGMENT](state, payload: PayloadAddSecuritySegment) {
add(state[STATE_SECURITY_SEGMENTS], payload, (x) => x.text);
},
[MUTATION_ADD_SECURITY_TERRITORY](state, payload: PayloadAddSecurityTerritory) {
add(state[STATE_SECURITY_TERRITORIES], payload, (x) => x.text);
},
[MUTATION_ADD_SECURITY_TYPE](state, payload: PayloadAddSecurityType) {
add(state[STATE_SECURITY_TYPES], payload, (x) => x.text);
},
[MUTATION_UPDATE_SECURITY](storeState, payload: PayloadUpdateSecurity) {
const state = storeState[STATE_SECURITIES];
const security = findById(state, payload.id)!;
storeActionValidator
.begin()
.while(StoreActions.Updating)
.throwIf(security)
.isUndefined(undefinedMessage("security", payload.id, state.index));
security.categoryId = payload.categoryId;
security.last = payload.last;
security.marketId = payload.marketId;
security.recommendation = payload.recommendation;
security.symbol = payload.symbol;
formatSecurity(security);
state.items = sort(state.items, (x) => x.symbol);
},
[MUTATION_UPDATE_SECURITY_CATEGORY](storeState, payload: PayloadUpdateSecurityCategory) {
const state = storeState[STATE_SECURITY_CATEGORIES];
const category = findById(state, payload.id)!;
storeActionValidator
.begin()
.while(StoreActions.Updating)
.throwIf(category)
.isUndefined(undefinedMessage("category", payload.id, state.index));
category.segmentId = payload.segmentId;
category.territoryId = payload.territoryId;
category.typeId = payload.typeId;
state.items = sort(state.items, (x) => x.text);
},
[MUTATION_UPDATE_SECURITY_MARKET](storeState, payload: PayloadUpdateSecurityMarket) {
const state = storeState[STATE_SECURITY_MARKETS];
const market = findById(state, payload.id)!;
storeActionValidator
.begin()
.while(StoreActions.Updating)
.throwIf(market)
.isUndefined(undefinedMessage("market", payload.id, state.index));
market.text = payload.text;
formatSecurityMarket(market);
state.items = sort(state.items, (x) => x.text);
},
[MUTATION_UPDATE_SECURITY_SEGMENT](storeState, payload: PayloadUpdateSecuritySegment) {
const state = storeState[STATE_SECURITY_SEGMENTS];
const segment = findById(state, payload.id)!;
storeActionValidator
.begin()
.while(StoreActions.Updating)
.throwIf(segment)
.isUndefined(undefinedMessage("segment", payload.id, state.index));
segment.text = payload.text;
state.items = sort(state.items, (x) => x.text);
},
[MUTATION_UPDATE_SECURITY_TERRITORY](storeState, payload: PayloadUpdateSecurityTerritory) {
const state = storeState[STATE_SECURITY_TERRITORIES];
const territory = findById(state, payload.id)!;
storeActionValidator
.begin()
.while(StoreActions.Updating)
.throwIf(territory)
.isUndefined(undefinedMessage("territory", payload.id, state.index));
territory.text = payload.text;
state.items = sort(state.items, (x) => x.text);
},
[MUTATION_UPDATE_SECURITY_TYPE](storeState, payload: PayloadUpdateSecurityType) {
const state = storeState[STATE_SECURITY_TYPES];
const type = findById(state, payload.id)!;
storeActionValidator
.begin()
.while(StoreActions.Updating)
.throwIf(type)
.isUndefined(undefinedMessage("type", payload.id, state.index));
type.text = payload.text;
state.items = sort(state.items, (x) => x.text);
},
};
...
SecuritiesDetails.vue (23:07)
<script lang="ts">
...
import {
ACTION_ADD_SECURITY,
ACTION_ADD_SECURITY_CATEGORY,
ACTION_ADD_SECURITY_MARKET,
ACTION_ADD_SECURITY_SEGMENT,
ACTION_ADD_SECURITY_TERRITORY,
ACTION_ADD_SECURITY_TYPE,
...
PayloadAddSecurity,
PayloadAddSecurityCategory,
PayloadAddSecurityMarket,
PayloadAddSecuritySegment,
PayloadAddSecurityTerritory,
PayloadAddSecurityType,
...
} from "@/store";
...
export default class SecuritiesDetails extends Vue {
@Action(ACTION_ADD_SECURITY) private readonly addSecurity!: ActionFn<PayloadAddSecurity>;
@Action(ACTION_ADD_SECURITY_CATEGORY) private readonly addCategory!: ActionFn<PayloadAddSecurityCategory>;
@Action(ACTION_ADD_SECURITY_MARKET) private readonly addMarket!: ActionFn<PayloadAddSecurityMarket>;
@Action(ACTION_ADD_SECURITY_SEGMENT) private readonly addSegment!: ActionFn<PayloadAddSecuritySegment>;
@Action(ACTION_ADD_SECURITY_TERRITORY) private readonly addTerritory!: ActionFn<PayloadAddSecurityTerritory>;
@Action(ACTION_ADD_SECURITY_TYPE) private readonly addType!: ActionFn<PayloadAddSecurityType>;
...
private save() {
switch (this.which) {
case SecurityDescriptors.Categories:
...
switch (this.id) {
case 0:
this.addCategory(category);
return;
...
}
return;
case SecurityDescriptors.Markets:
...
switch (this.id) {
case 0:
this.addMarket(market);
return;
...
}
return;
case SecurityDescriptors.Securities:
...
switch (this.id) {
case 0:
this.addSecurity(security);
return;
...
}
return;
case SecurityDescriptors.Segments:
...
switch (this.id) {
case 0:
this.addSegment(segment);
return;
...
}
return;
case SecurityDescriptors.Territories:
...
switch (this.id) {
case 0:
this.addTerritory(territory);
return;
...
}
return;
case SecurityDescriptors.Types:
...
switch (this.id) {
case 0:
this.addType(type);
return;
...
}
return;
}
}
}
</script>
Exciton Interactive LLC