Vuejs 2 two connected components unit/integration testing - javascript

I have 2 Vuejs components that are connected to each other. The first component is updating data in the second one. What is the best approach for integration testing? I am using vuejs 2.
VoucherComponent:
import Store from '../store';
import Ajax from '../_helpers/ajax';
const Voucher = {
name: 'voucher',
props: ['id'],
template: '',
data () {
return {
voucherCode: null,
priceDetails: Store.priceDetails,
vouchers: Store.vouchers
}
},
beforeCreate() {
Store.vouchers = []
},
methods: {
validateVoucher() {
let totalPrice = Store.total;
let vouchers = this.vouchers;
let voucherCode = this.voucherCode;
let id = this.id;
let priceDetails = this.priceDetails;
let voucher = new Ajax('/vouchers/redeem/' + voucherCode + '/' + id + '/' + totalPrice + '/', 'GET');
if (!this.checkVoucherPriceDetails()) {
voucher.ajaxCall(function (response) {
if (!response.error) {
vouchers.push({
code: voucherCode,
value: parseFloat(response.data.discount).toFixed(2),
type: 'voucher',
name: 'voucher',
description: 'Your voucher code: ' + voucherCode
});
priceDetails.push({
code: voucherCode,
price: parseFloat((-1.00 * response.data.discount)).toFixed(2),
description: 'Your voucher code: ' + voucherCode,
type: 'voucher'
});
} else {
return false;
}
});
}
},
removeVoucher(voucher) {
this.voucherCode = voucher.code;
this.clearVouchersFromPriceDetails();
var stringifyVoucher = JSON.stringify(voucher);
for (var i = 0, len = this.vouchers.length; i < len; i++) {
if (stringifyVoucher === JSON.stringify(this.vouchers[i])) {
this.vouchers.splice(i, 1);
break;
}
}
// return true;
},
clearVouchersFromPriceDetails() {
for (var i = this.priceDetails.length - 1; i >= 0; i--) {
if (this.priceDetails[i].code === this.voucherCode) {
this.priceDetails.splice(i, 1);
}
}
},
checkVoucherPriceDetails() {
for (var i = this.priceDetails.length - 1; i >= 0; i--) {
if (this.priceDetails[i].code === this.voucherCode) {
return true;
}
}
return false;
}
},
mounted () {
Store.debug && console.log("Init voucher component");
}
};
export default Voucher;
PriceDetailsComponent:
import Store from '../store';
const PriceDetails = {
name: 'price-details',
props: ['price','fee'],
data() {
return {
priceDetails: Store.priceDetails,
store: Store
}
},
created() {
this.priceDetails.push({
price: this.price.toFixed(2),
description: "Buchung Preis",
type: 'booking'
});
this.priceDetails.push({
price: this.fee.toFixed(2),
description: "Buchungsgebühren",
type: 'booking_fee'
});
},
computed: {
totalPrice() {
let total = 0.00;
let insurancePrice = 0.00;
for (var detailKey in this.priceDetails) {
var detail = this.priceDetails[detailKey];
total += parseFloat(detail.price);
if (detail.type == 'insurance') {
insurancePrice = detail.price;
}
this.store.total = total;
}
return parseFloat(total).toFixed(2);
}
},
mounted() {
Store.debug && console.log("Init price-details");
}
};
export default PriceDetails;
Store:
const Store = {
debug: true,
priceDetails: [],
total: 0.00
};
export default Store;
Thanks a lot!

Related

Vue infinite UI update loop with function as param

I'm new in Vue.js and tried to convert some legacy code for pagination. I've created a pager component which accepts a function as one of its params. But it's causing an infinite UI render loop.
Could you help me to resolve or suggest some solution for such problem?
Here is my pager component js:
const PagerComponent = {
name: "pagerComponent",
template: "#pagerComponent",
props: {
pageSize: Number,
pageIndex: Number,
totalPages: Number,
totalRecords: Number,
pageSlide: Number,
hasNextPage: Boolean,
hasPrevPage: Boolean,
pages: Array,
loadFunc: Function
},
data() {
return {
pager: {
pageSize: 0,
pageIndex: 0,
totalPages: 0,
totalCount: 0,
pageSlide: 1,
hasNextPage: false,
hasPrevPage: false,
pages: [],
loadFunc: function () { }
}
}
},
methods: {
load(index) {
this.pager.pageIndex = index;
if (this.pager.loadFunc != null) {
this.pager.loadFunc();
}
},
isActivePage(page) {
return this.pager.pageIndex + 1 == page;
},
update(newPager) {
this.pager.pageSize = newPager.pageSize;
this.pager.pageIndex = newPager.pageIndex;
this.pager.totalPages = newPager.totalPages;
this.pager.totalCount = newPager.totalCount;
this.pager.hasNextPage = newPager.hasNextPage;
this.pager.hasPrevPage = newPager.hasPrevPage;
this.generatePages();
},
generatePages() {
this.pager.pages = [];
var pageNum = this.pager.pageIndex + 1;
var pageFrom = Math.max(1, pageNum - this.pager.pageSlide);
var pageTo = Math.min(this.pager.totalPages, pageNum + this.pager.pageSlide);
pageFrom = Math.max(1, Math.min(pageTo - this.pager.pageSlide, pageFrom));
pageTo = Math.min(this.pager.totalPages, Math.max(pageFrom + this.pager.pageSlide, pageNum == 1 ? pageTo + this.pager.pageSlide : pageTo));
for (var i = pageFrom; i <= pageTo; i++) {
this.pager.pages.push(i);
}
}
},
computed: {
hasPages() {
if (this.pager.pages == null)
return false;
return this.pager.pages.length > 0;
},
doNotHavePrevPage() {
return !this.pager.hasPrevPage;
},
doNotHaveNextPage() {
return !this.pager.hasNextPage;
}
},
beforeMount() {
this.pager.pageSize = this.pageSize;
this.pager.pageIndex = this.pageIndex;
this.pager.totalPages = this.totalPages;
this.pager.totalCount = this.totalRecords;
this.pager.hasNextPage = this.hasNextPage;
this.pager.hasPrevPage = this.hasPrevPage;
this.pager.loadFunc = this.loadFunc;
this.pager.pages = this.pages || [];
this.generatePages();
},
mounted() {
}
}
Here is how it's used in html:
<pager-Component v-bind="Pager" v-bind:load-Func="GetItems" ref="pager"></pager-Component>
And GetItems funciton:
function () {
var self = this;
const data = {
Pager: self.Pager,
Filter: []
};
$.ajax({
url: self.GetItemsUrl,
type: "POST",
dataType: "json",
busy: self.Loading,
data: data
}).done(function (result) {
if (result.isSuccess) {
self.$refs.pager.update(result.data.pager);
self.Items.splice(0);
result.data.items.map(function (value, key) {
self.Items.push(value);
});
}
else {
alert(result.data.errors[0]);
}
});
}
Finally after tones of tests, the solution was found and it's pretty easy.
I just needed to use v-on:click instead of :click. I just don't know why lot of tutorials suggest to use :click if it doesn't work
So for example use
<div v-on:click="load(pageIndex)">My button</div>
instead of
<div :click="load(pageIndex)">My button</div>

Vuex store creates a new instance when imported in different modules

I'm struggling for a few days with importing my Vuex store into multiple different modules. For some reason it seems that my store is creating new instances for every import. In one Vue object i am setting a value to the store, but for an unknown reason to me it is not accessible in another Vue object. I have 3 files: store.js, addresses.js, and relation.js. In the store.js file the following code is present:
const Vue = require('vue').default;
const Vuex = require("vuex");
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
addresses: {
address: 'test'
}
},
mutations: {
setAddress(state, payload) {
state.addresses.address = payload;
}
},
actions: {
setAddress(state, payload) {
state.commit('setAddress', payload);
}
},
getters: {
getAddress(state) {
return state.addresses.address;
}
},
});
export default store;
My addresses.js contains:
import agent from '../agent.js';
const Vue = require("vue").default;
import __ from '../translations/translate';
import Swal from '../../../app-assets/vendors/js/extensions/sweetalert2.all.min'
import store from "../store";
var address = new Vue({
el: '#address-form',
data: {
address: {
id: null,
postal_code: '',
house_number: '',
house_number_addition: '',
street_name: '',
place: '',
country: defaultAddressCountry[0],
latitude: null,
longitude: null,
extra_address_line: null,
safety_instructions: null,
notes: null,
po_box_number: '',
is_po_box: false
},
address_countries: addressCountries,
inputErrors: {
postal_code: '',
house_number: '',
street_name: '',
place: '',
po_box_number: '',
}
},
methods: {
completeAddress: function(){
let self = this;
if(this.address.postal_code && this.address.house_number && this.address.postal_code.length > 3 && this.address.house_number.length > 0){
$('#complete-address i').addClass('rotate');
agent.Address.completeAddress(this.address.postal_code, this.address.house_number.toString() + this.address.house_number_addition, this.address.country)
.then(function(response){
self.address.street_name = response.data.address.street;
self.address.place = response.data.address.locality;
self.address.latitude = response.data.location.latitude;
self.address.longitude = response.data.location.longitude;
$('#complete-address i').removeClass('rotate');
self.validateFields();
}).catch(function(){
$('#complete-address').addClass('text-color-red');
setTimeout(function(){
$('#complete-address').removeClass('text-color-red');
}, 1000)
$('#complete-address i').removeClass('rotate');
self.address.street_name = null;
self.address.place = null;
self.address.latitude = null;
self.address.longitude = null;
});
}else{
if(!this.address.postal_code || this.address.postal_code.length <= 4){
$('#input-postal-code').addClass('has-error');
}
if(!this.address.house_number || this.address.house_number.length == 0){
$('#input-house-number').addClass('has-error');
}
setTimeout(function(){
$('#input-postal-code, #input-house-number').removeClass('has-error');
}, 500)
}
},
gotoMaps: function () {
open('https://maps.google.com/?q=' + this.address.latitude + ', ' + this.address.longitude);
},
sanitizeFields: function(){
this.address.postal_code = this.address.postal_code.replace(/[^0-9a-z]/gi, '').toUpperCase().substr(0, 6);
this.address.house_number = this.address.house_number.replace(/[^0-9]+/g, '').substr(0, 4);
this.address.house_number_addition = this.address.house_number_addition.replace(/[^0-9a-z]/gi, '').toUpperCase().substr(0, 2);
},
validateFields: function(){
let has_errors = false;
this.inputErrors.postal_code = '';
if(this.address.postal_code.length < 5){
this.inputErrors.postal_code = __('invalid input');
has_errors = true;
}
if(this.address.postal_code.length === 0){
this.inputErrors.postal_code = __('required');
has_errors = true;
}
this.inputErrors.house_number = '';
if(this.address.house_number.length === 0 && !this.address.is_po_box){
this.inputErrors.house_number = __('required');
has_errors = true;
}
this.inputErrors.street_name = '';
if(this.address.street_name.trim().length === 0 && !this.address.is_po_box){
this.inputErrors.street_name = __('required');
has_errors = true;
}
this.inputErrors.place = '';
if(this.address.place.trim().length === 0){
this.inputErrors.place = __('required');
has_errors = true;
}
this.inputErrors.po_box_number = '';
if(this.address.po_box_number.trim().length === 0 && this.address.is_po_box){
this.inputErrors.po_box_number = __('required');
has_errors = true;
}
return !has_errors;
},
saveAddress: function(){
if(this.address.is_po_box){
this.address.street_name = '';
this.address.house_number = '';
this.address.house_number_addition = '';
this.address.safety_instructions = null;
this.address.extra_address_line = null;
this.address.notes = null;
}else{
this.address.po_box_number = '';
}
if(this.validateFields()){
let self = this;
if(this.address.id) {
agent.Address.update(this.address);
}else{
agent.Address.create(this.address).then(function (result) {
if(result.status)
self.address = result.data;
}).catch(function(error){
if(error.response.status === 409){
let house_number = [error.response.data.house_number];
if(error.response.data.house_number_addition){
house_number.push(error.response.data.house_number_addition);
}
Swal.fire({
title: __('Existing address was found'),
icon: 'info',
html: '' +
'<table style="text-align:left;" class="table table-bordered">' +
'<tr>' +
'<td>'+__('Address')+'</td>' +
'<td>'+error.response.data.street_name+' ' + house_number.join('-') + '</td>' +
'</tr>' +
'<tr>' +
'<td>'+__('Postal code')+'</td>' +
'<td>'+error.response.data.postal_code+'</td>' +
'</tr>' +
'<tr>' +
'<td>'+__('Place')+'</td>' +
'<td>'+error.response.data.place+'</td>' +
'</tr>' +
'<tr>' +
'<td>'+__('Country')+'</td>' +
'<td>'+error.response.data.country+'</td>' +
'</tr>' +
'</table>',
customClass: 'swal-wide',
showCancelButton: true,
confirmButtonText: __('Use this address'),
cancelButtonText: __('No, create a new one'),
}).then(function(result){
if(result.value === true){
store.dispatch('setAddress', self.address)
console.log(store.state.addresses.address)
}
});
}
});
}
}
}
},
watch: {
address: {
handler(){
if(this.address.is_po_box){
$('.no-po-box').hide();
$('#extra-address-info').hide();
$('#show-address-extra').attr('data-expanded', 'false');
$('#show-address-extra').find('i').removeClass('icon-chevron-up').addClass('icon-chevron-down');
$('.is-po-box').show();
}else{
$('.no-po-box').show();
$('.is-po-box').hide();
}
this.sanitizeFields();
},
deep: true
}
},
computed: {
showMapsIcon: function(){
return this.address.latitude && this.address.longitude;
}
},
created(){
$(document).on('click', '.address-selector', function(){
$('#address-modal').modal();
});
$(document).on('click', '#show-address-extra', function(){
if($(this).attr('data-expanded') == 'false') {
$('#extra-address-info').slideDown();
$(this).attr('data-expanded', 'true');
$(this).find('i').removeClass('icon-chevron-down').addClass('icon-chevron-up');
}else{
$('#extra-address-info').slideUp();
$(this).attr('data-expanded', 'false');
$(this).find('i').removeClass('icon-chevron-up').addClass('icon-chevron-down');
}
});
$('.dataTable').DataTable();
},
delimiters: ['[[' , ']]']
});
export default address;
My relation.js file:
import agent from '../../agent.js'
const Vue = require("vue").default;
import store from "../../store";
var relation = new Vue({
el: '#upsert-relation-form',
data: {
relation: {
id: null,
name: null,
is_supplier: false,
is_customer: true,
is_prospect: false,
is_debtor: true,
general_email_address: null,
general_phone_number: defaultCountryCode,
communication_language: languages.find(x => x.code == defaultLanguage[0])['code'],
account_manager: null,
tags: [],
industries: [],
},
languages: languages,
account_managers: [
{
id: 1,
name: 'Piet de Vries'
},
{
id: 2,
name: 'Willem Aardappel'
}
]
},
computed: {
visiting_address(){
console.log(store.getters.getAddress);
return store.getters.getAddress;
}
},
methods: {
completeAddress: function(address){
console.log(address);
}
},
created(){
let self = this;
$(document).on('click', '.tags-container', function(){
$(this).find('input').focus();
});
$(document).on('click', '.tags-container li a.remove', function(){
let field = $(this).closest('.tags-container').attr('data-field');
let val = $(this).closest('li').text().trim();
let index = self.relation[field].findIndex(function(tag){
return tag.value == val;
});
self.relation[field].splice(index, 1);
});
$(document).on('keyup', '.tags-container input', function(e){
let field = $(this).closest('.tags-container').attr('data-field');
if(e.keyCode === 13){
let tagValue = $(this).val().trim().toLowerCase().replace(/[^a-zA-Z 0-9]+/g, '');
if(tagValue.length < 3){
return;
}
let index = self.relation[field].findIndex(function(tag){
return tag.value == tagValue;
});
if(index !== -1){
$(this).val('');
return;
}
self.relation[field].push({
id: null,
value: tagValue
});
$(this).val('');
}
});
$(document).on('keydown', '.tags-container input', function(e){
let field = $(this).closest('.tags-container').attr('data-field');
if(e.keyCode === 8 && $(this).val().trim().length === 0){
self.relation[field].pop();
}
});
},
delimiters: ['[[' , ']]']
});
export default relation;
In addresses.js I see that the value is correctly set to the store. But in the relation.js file it still gets the original data set on initiation of the store.
It's supposed to be done the other way around, you import the module in your vuex and not the vuex in your module.
So you should have a "Master module" that looks like this:
import Vue from 'vue';
///////////Vuex et store
import Vuex from 'vuex';
/////////////////Modules
import media from "./modules/media";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
},
getters: {
},
mutations: {
}
,
actions: {
},
modules: {
media
}
})
and then your module should simply be like so:
const state = {
};
const getters = {
};
const mutations = {
};
const actions = {
};
export default {
namespaced: true,
state,
getters,
actions,
mutations
};
The namespaced part is optional and here is the link to the doc:
https://vuex.vuejs.org/fr/guide/modules.html
In the doc it's organised in a single file, the way I presented it correspond to one file for the "Master Module" which is your store really, and then a file by module.

How to dispatch a Vue computed property

I´m trying to dispatch an object which is created in a computed.
I can´t get it to work as I´m fairly new to vue.js
I want to dispatch the object "updateObject" to the vuex-store.
Tried with setters but didn´t work. I think if I can set the "varia" object to the same object like "updateObject" then I could maybe dispatch it?
Hope somebody can help me.
Here is my code:
<template>
<div class="detail">
<b-row align-v="center"><b-button variant="success" #click="submit()">submit</b-button></b-row>
// some more code...
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
data () {
return {
subID: '',
res: '',
showAlert: true,
varia: null
}
},
computed: {
...mapState([
'FA',
'Main',
'Sub',
'layouttype'
]),
getVariable: function (Sub, layouttype) {
const subID = this.layouttype.sub_id
var filterObj = this.Sub.filter(function (e) {
return e.sub_id === subID
})
console.log(filterObj)
return filterObj
},
updateObject: {
// getterfunction
get: function () {
var len = this.getVariable.length
var res = []
for (var i = 0; i < len; i++) {
if (i in this.getVariable) {
var val = this.getVariable[i].variable
res.push(val)
}
}
console.log(res)
var ergebnis = {}
res.forEach(key => {
if (this.FA[key]) {
ergebnis[key] = this.FA[key]
}
})
return ergebnis
},
// setterfunction
set: function (value) {
this.varia = value
}
}
},
methods: {
submit () {
this.$store.dispatch('sendData', this.ergebnis)
}
}
}
</script>
It tell´s me "this.ergebnis" is undefined
You can try it declaring "ergebnis" as global variable under data as
export default {
data () {
return {
subID: '',
res: '',
showAlert: true,
varia: null,
ergebnis : {}
}
},
computed: {
...mapState([
'FA',
'Main',
'Sub',
'layouttype'
]),
getVariable: function (Sub, layouttype) {
const subID = this.layouttype.sub_id
var filterObj = this.Sub.filter(function (e) {
return e.sub_id === subID
})
console.log(filterObj)
return filterObj
},
updateObject: {
// getterfunction
get: function () {
var len = this.getVariable.length
var res = []
for (var i = 0; i < len; i++) {
if (i in this.getVariable) {
var val = this.getVariable[i].variable
res.push(val)
}
}
console.log(res)
res.forEach(key => {
if (this.FA[key]) {
this.ergebnis[key] = this.FA[key]
}
})
return this.ergebnis
},
// setterfunction
set: function (value) {
this.varia = value
}
}
},
methods: {
submit () {
this.$store.dispatch('sendData', this.ergebnis)
}
}
}
Now ergebnis is accessible

how can i change row color in react

export class EstimateForm extends React.Component<IEstimateFormProps,
IEstimateFormState> {
state: IEstimateFormState = {
cellUpdateCss: 'red',
toRow: null,
fromRow: null,
estimateList: null,
estimateItemList: [],
poseList: null,
levelList: null,
partList: null,
selectedEstimate: null,
totalEstimateItems: 0,
selectedIndexes: [],
totalEstimateAmount: 0,
grid: null,
projectId: 0,
};
constructor(props, context) {
super(props, context);
this.state.estimateList = this.props.estimateList;
}
rowGetter = i => {
const row = this.state.estimateItemList[i];
const selectRevison = this.state.selectedEstimate.revision;
if (row['pose.poseName']) {
const poseCode = row['pose.poseName'].substring(row['pose.poseName'].lastIndexOf('[') + 1, row['pose.poseName'].lastIndexOf(']'));
for (const pose of this.state.poseList) {
if (pose.poseCode === poseCode) {
row.pose = pose;
}
}
}
if (row['level.levelName']) {
const levelCode = row['level.levelName'].substring(
row['level.levelName'].lastIndexOf('[') + 1,
row['level.levelName'].lastIndexOf(']')
);
for (const level of this.state.levelList) {
if (level.levelCode === levelCode) {
row.level = level;
}
}
}
if (row['level.part.partName']) {
const partCode = row['level.part.partName'].substring(
row['level.part.partName'].lastIndexOf('[') + 1,
row['level.part.partName'].lastIndexOf(']')
);
for (const part of this.state.partList) {
if (part.partCode === partCode) {
row.part = part;
}
}
}
row.get = key => eval('row.' + key);
row.totalCost = (row.materialCost + row.laborCost) * row.amount;
if (row.revision > selectRevison) {
for (let i = 0; i < row.length; i++) {
row[i].style.color = 'red'; // here color is nor change
}
return row;
} else {
return row;
}
}
handleGridRowsUpdated = ({ fromRow, toRow, updated }) => {
const rows = this.state.estimateItemList.slice();
for (let i = fromRow; i <= toRow; i++) {
const rowToUpdate = rows[i];
const updatedRow = update(rowToUpdate, { $merge: updated });
rows[i] = updatedRow;
}
this.setState({ estimateItemList: rows, fromRow: (fromRow), toRow: (toRow)
}, () => {
});
};
saveEstimateItems = () => {
if (this.state.selectedEstimate == null) {
toast.warn(<Translate
contentKey="bpmApp.estimateForm.pleaseSelectEstimate">Please select an
estimate</Translate>);
return;
}
render() {
return ()
}
I wanna to change the row color when the condition row.revision > this.state.selectedEstimate.revision . How can I prevent the change of this.color. However im not get any error but row color is not change. how can i solve this problem it is my first project in react and i dont know where is the problemThanks for your feedback guys.

v2.canGoForward is not a function

I am trying to move the code vm.canGoForward from my controller to a service to hide the implementation details.
BEFORE CODE CHANGE
This worked fine.
View:
<button ng-disabled="!vm.canGoForward()" class="btn btn-primary" name="next" type="button" ng-click="vm.gotoStep(vm.currentStep + 1)">
Controller:
var vm = this;
vm.currentStep = 1;
vm.steps = WizardService.getWizardSteps(vm.formData);
vm.canGoForward = function() {
var res = true,
i,
nextStateIndex = vm.currentStep + 1;
if (nextStateIndex > vm.steps.length) {
return false;
}
for (i = 1; res && i <= nextStateIndex; i++) {
res = (res && vm.steps[i-1].isReady());
}
return !!res;
};
Service
var wizardService = {
getWizardSteps: getWizardSteps
};
return wizardService;
function getWizardSteps(formData) {
var wizardSteps = [
{
step: 1,
name: 'Name',
template: 'views/wizard/step1.html',
isReady: function() { return true; }
},
{
step: 2,
name: 'Email',
template: 'views/wizard/step2.html',
isReady: function() { return formData.firstName && formData.lastName; }
},
{
step: 3,
name: 'Job Category',
template: 'views/wizard/step3.html',
isReady: function() { return formData.email; }
}
];
return wizardSteps;
}
AFTER CODE CHANGE
View
Remains the same
Controller
var vm = this;
vm.currentStep = 1;
vm.steps = WizardService.getWizardSteps(vm.formData);
vm.canGoForward = WizardService.canGoForward(vm.currentStep, vm.steps);
Service
var wizardService = {
getWizardSteps: getWizardSteps,
canGoForward: canGoForward
};
return wizardService;
function getWizardSteps(formData) {
var wizardSteps = [
{
step: 1,
name: 'Name',
template: 'views/wizard/step1.html',
isReady: function() { return true; }
},
{
step: 2,
name: 'Email',
template: 'views/wizard/step2.html',
isReady: function() { return formData.firstName && formData.lastName; }
},
{
step: 3,
name: 'Job Category',
template: 'views/wizard/step3.html',
isReady: function() { return formData.email; }
}
];
return wizardSteps;
}
function canGoForward(currentStep, steps) {
console.log(steps);
var res = true,
i,
nextStateIndex = currentStep + 1;
if (nextStateIndex > steps.length) {
return false;
}
for (i = 1; res && i <= nextStateIndex; i++) {
res = (res && steps[i-1].isReady());
}
return !!res;
}
I now get the following error: TypeError: v2.canGoForward is not a function. How can I resolve it?
In your second version, the following line will actually call WizardService.canGoForward on the spot, not assign it:
vm.canGoForward = WizardService.canGoForward(vm.currentStep, vm.steps);
What gets assigned is the return value of that call, which obviously is not a function, hence the error message when a call is attempted later.
If you want to assign the function, and ensure the arguments get passed when it is called later, then use bind:
vm.canGoForward = WizardService.canGoForward.bind(WizardService, vm.currentStep, vm.steps);

Categories

Resources