VUE - prop binding for "disabled" not working on select field - javascript

I am trying to make a drop down "select" field disabled under certain conditions in my app.
I have successfully done this with buttons already using a prop (disableBtn) that i pass up from the root of my app to the button component I made.
I try to do the EXACT same thing on a select component and it refuses to pass the prop (disableOption) back into the child component, even though its passing back many other binded props that work fine and build the options out in the drop down correctly.
I am logging the values on screen right now and can see they are updating in the main app component, but its not passing that back to the child for some reason.
Where am I off here? My understanding is you store the values you want to change in data() in the app.vue, then create a prop for them in the child component and bind them in the HTML. This has been working fine in all my other use cases.
app.vue
<template>
<div class="container">
<img alt="logo" src="./assets/logo.png">
<Header title="Provider Manager" :custTZ="custTZ" :shippingState="shippingState" :patientID="patientID" :custName="custFullName" :custEmail="custEmail" :custPhone="custPhone" />
<div v-if="providerVisibility" class="providerInfo">
<Button #btn-click="providerPicked" id="first-avail" text="First Available" />
<br />
<Select #dd-select="providerPickedSelect" :disabled="disableOption" :selectName="selectName" :id="id" :eligibleProviders="eligibleProviders" :labelFor="labelFor" :labelText="labelText" />
{{ disableOption }}
</div>
<div v-if="providerSelected" >
<hr>
<br />
<h2>Provider: {{ chosenProvider }} </h2>
<br />
</div>
<div v-if="providerSelected" >
<BookingSlots #selectSlot="removeUnselected" :slots="slots" />
<br />
<Button #btn-click="bookMeeting" text="Confirm Request" />
</div>
</div>
</template>
<script>
import { ZOHO } from "./assets/ZohoEmbededAppSDK.min.js";
import Header from './components/Header'
import Button from './components/Button'
import BookingSlots from './components/BookingSlots'
import Select from './components/Select'
const axios = require('axios');
export default {
name: 'App',
components: {
Header,
Button,
BookingSlots,
Select
},
data() {
return{
slots: [],
providerVisibility: true,
providerSelected: false,
currentProvider: 'None Assigned',
chosenProvider: '',
custFullName: '',
custEmail: '',
custPhone: '',
shippingState: '',
patientID: '',
custTZ: '',
providerZID: '',
eligibleProviders: [],
disableBtn: false,
disableOption: true,
}
},
methods: {
removeUnselected(id) {
console.log('id', id)
this.slots = this.slots.filter((slot) => slot.id === id)
},
providerPicked(id) {
console.log("id" + id)
console.log("currentProvider",this.currentProvider)
//Toggle front end visibility
this.providerSelected = true;
this.providerVisibility = false;
if(id === "first-avail"){
// hit booking engine, get name of first available
console.log("FIRST AVAIL")
this.chosenProvider = "Need to Hit Booking App";
}
if(id === "current-provider"){
// hit zoho values and get contact assigned provider
console.log("CURRENT PROVIDER")
this.chosenProvider = this.currentProvider;
}
},
providerPickedSelect(id, selectValue) {
if(this.id === "provider-select"){
// Get values from our DB for the provider selected
console.log("Provider-Select")
this.providerSelected = true;
this.providerVisibility = false;
this.chosenProvider = selectValue;
}
},
bookMeeting() {
//Book the meeting
console.log("book meeting called")
}
},
created() {
//Hit zoho and get customer info back
ZOHO.embeddedApp.on("PageLoad",(data) =>
{
console.log(data);
//Custom Business logic goes here
let entity = data.Entity;
let recordID = data.EntityId[0];
ZOHO.CRM.API.getRecord({Entity:entity,RecordID:recordID})
.then((data) => {
console.log(data.data[0])
// Set values scraped from CRM Contact profile
if(data.data[0].provider !== null && data.data[0].provider !== "None Assigned" ){
this.currentProvider = data.data[0].provider.name;
this.providerZID = data.data[0].provider.id;
}else{
//need to disable button if no doc assigned
this.disableBtn = true;
}
this.custEmail = data.data[0].Email;
this.custFullName = data.data[0].Full_Name;
this.custPhone = data.data[0].Phone;
this.patientID = data.data[0].Patient_ID;
this.shippingState = data.data[0].Mailing_State;
this.custTZ = data.data[0].GTM;
// getEligibleProviders(this.shippingState);
var data = JSON.stringify({
"state":this.shippingState,
});
axios(config)
.then((res) => {
console.log(res.data)
//this.eligibleProviders = res.data;
if(this.eligibleProviders && !this.eligibleProviders.length){
console.log("empty array")
this.eligibleProviders = [{
first_name: "None Avilable in Svc. State",
last_name: ""
}
];
this.disableOption = true;
}else{
console.log("full array")
}
console.log(this.eligibleProviders)
})
.catch((e) => {
console.log(e);
});
});
});
ZOHO.embeddedApp.init();
this.slots = [
{
id: 1,
text: 'Time Slot 1',
providerFname: 'James',
providerLname: "Appleton"
},
{
id: 2,
text: 'Time Slot 2',
providerFname: 'James',
providerLname: "Johnson"
}
];
this.selectName = "provider-select";
this.id = "provider-select";
this.labelFor = "provider-select";
this.labelText = "Choose a Provider: ";
}
}
</script>
select.vue
<template>
<br />
<label :for="labelFor">{{ labelText }} {{ disableOption }}</label>
<select v-on:change="onSelect($event, id)" class="select" :name="selectName" :id="id" :disabled="disableOption" >
<option :value="'none'" selected disabled hidden >Select One</option>
<option :key="provider.id" v-for="provider in eligibleProviders" :value="provider.first_name + ' ' + provider.last_name" >{{ provider.first_name +" "+ provider.last_name }}</option>
</select>
<br /><br />
</template>
<script>
export default {
name: 'Select',
props: {
selectValue: String,
selectName: String,
id: String,
labelFor: String,
labelText: String,
eligibleProviders: Array,
disableOption: Boolean,
},
methods: {
onSelect($event, id) {
console.log($event.target.value)
this.$emit('dd-select', id, $event.target.value);
}
},
emits: ['dd-select']
}
</script>
button.vue
<template>
<button #click="onClick(id)" class="btn" :id="id" :disabled="disableBtn" >{{ text }}</button>
</template>
<script>
export default {
name: 'Button',
props: {
text: String,
id: String,
disableBtn: Boolean,
},
methods: {
onClick(id) {
this.$emit('btn-click', id);
}
}
}
</script>

in select.vue, the props says it wants "disableOption", but you're passing disabled="disableOption"
so you can try updating app.vue with:
<Select
#dd-select="providerPickedSelect"
:disable-option="disableOption"
:select-name="selectName"
:id="id"
:eligible-providers="eligibleProviders"
:label-for="labelFor"
:label-text="labelText"
/>

Related

Nuxtjs: Axios Request does not work when switching to another route

i try to build a little clothing web shop with nuxtjs. You can choose the color on the details page. The details page represents a pice of clothing. The ColorMenu is a component. If you choose something a color, it will emit it back to the details page and will send a new details request to my backend.
However, changing the color only works if you don't choose another piece of clothing. If you choose another piece of clothing (so the route parameters will change) and choose another color in the menu, there is a always an error that it cannot load anything. it seems that it sends repeated requests until the request is blocked.
The details routes are built according to this scheme: localhost/details/{sellableId}/{ideaId}/{appearanceId}
Details Page:
<template>
<section class="section">
<div v-if="details">
<div class="columns">
<div class="column">
<ImageCaroussel :images="details.images"></ImageCaroussel>
</div>
<div class="column">
<h3>Farben</h3>
<ColorMenu
:appearances="productType.appearances"
:appearanceIds="details.appearanceIds"
></ColorMenu>
</div>
</div>
</div>
</section>
</template>
<script>
import { mapState } from 'vuex'
import Dropdown from '~/components/details/Dropdown.vue'
import ColorMenu from '~/components/details/ColorMenu.vue'
import ImageCaroussel from '~/components/details/ImageCaroussel.vue'
export default {
created() {
this.$nuxt.$on('selected', ($event) => (this.selected = $event))
this.$nuxt.$on('selectedColor', ($event) => this.setSelectedColor($event))
},
data() {
return {
modal: false,
selected: '',
selectedColor: '',
}
},
async asyncData({ store, params }) {
console.log('asyncfirst')
if (params.sellableId && params.appearanceId && params.ideaId) {
await store.dispatch('details/get_details', {
sellableId: params.sellableId,
appearanceId: params.appearanceId,
ideaId: params.ideaId,
})
let sellableId = params.sellableId
let appearanceId = params.appearanceId
let ideaId = params.ideaId
console.log('asyncsecond!')
return { sellableId, appearanceId, ideaId }
}
},
mounted() {
this.sellableId = this.$route.params.sellableId
this.appearanceId = this.$route.params.appearanceId
this.ideaId = this.$route.params.ideaId
console.log('Mounted!')
},
components: {
Dropdown,
ColorMenu,
ImageCaroussel,
},
computed: {
...mapState({
details: (state) => {
return state.details.details
},
currency: (state) => {
return state.sellable.currency
},
productType: (state) => {
return state.details.productType
},
}),
},
methods: {
checkout: async function (sellableId, size, appearanceId) {
let link = await this.$backendrepositories.basket.checkout(
sellableId,
size,
appearanceId
)
if (link.status === 200 && link.data) {
this.modal = true
setTimeout(() => {
window.location.href = link.data.link
}, 3000)
}
},
setSelectedColor: async function (event) {
this.selectedColor = event
await this.$store.dispatch('details/get_details', {
sellableId: this.sellableId,
appearanceId: this.selectedColor,
ideaId: this.ideaId,
})
},
},
}
</script>
ColorMenu Component:
<template>
<div>
<div
v-for="(cell, index) in appearances"
:key="index"
style="display: inline-block"
>
<label v-if="appearanceIds.includes(cell.id)" class="self-container">
<input type="radio" checked="checked" name="color" />
<span
class="checkmark"
:style="`background-color: ${cell.colors[0].value}`"
#click="select(cell.id)"
></span>
</label>
</div>
</div>
</template>
<script>
export default {
data: function () {
return {
selected: '',
}
},
props: ['appearances', 'appearanceIds'],
methods: {
select(select) {
this.selected = select
this.$nuxt.$emit('selectedColor', this.selected)
},
},
}
</script>
There is a live demo at https://akano-frontend.vercel.app/

Vue 3 component not rendering but show up on the elements tree

I'm new to vue and I was trying to change one of my components in to the new syntax to learn vue 3. The component was working just fine before the change so I must be missing something.
this is the mother component:
<template>
<div class="user-profile">
<div>
<div class="user-profile__user-panel">
<h1 class="user-profile__username">#{{ user.username }}</h1>
<div v-if="user.isAdmin" class="user-profile__admin-badge">Admin</div>
<div class="user-profile__follower-count">
<string><b>Followers: </b></string> {{ followers }}
</div>
</div>
<NewTwoot #create-twoot="createNewTwoot" />
</div>
<div class="user-profile__twoots-wraper">
<TwootItem
v-for="twoot in user.twoots"
:username="user.username"
:key="twoot.id"
:twoot="twoot"
#favorit="toggleFavorite(id)"
/>
</div>
</div>
</template>
<script>
import TwootItem from "./TwootItem.vue";
export default {
name: "UserProfile",
components: {
TwootItem,
},
data() {
return {
followers: 0,
user: {
id: 1,
username: "GabrielBG",
firstName: "Gabriel",
lastName: "Gutierrez",
email: "gbg#scienceiscoll.com",
isAdmin: true,
twoots: [
{
id: 2,
content: "This is my second twoot",
},
{
id: 3,
content: "This is my third twoot",
},
{
id: 1,
content: "This is my first twoot",
},
],
},
};
},
watch: {
followers(newFollowerCount, oldFollowerCount) {
if (oldFollowerCount > newFollowerCount) {
console.log("You lost a follower!");
} else {
console.log("You gained a follower!");
}
},
},
computed: {
fullName() {
return this.user.firstName + " " + this.user.lastName;
},
},
methods: {
followUser() {
this.followers++;
},
toggleFavorite(id) {
console.log("Toggling favorite for twoot with id: " + id);
},
createNewTwoot(newTwootContent) {
this.user.twoots.unshift({
id: this.user.twoots.length + 1,
content: newTwootContent,
});
},
},
mounted() {
this.followUser();
},
};
</script>
And this is the component that was refactored but now it does not render:
<template>
<form class="create-twoot" #submit.prevent="createNewTwoot">
<lable for="new-twoot"
><strong>New Twoot</strong> ({{ newTwootCharCount }}/180)
</lable>
<textarea id="new-twoot" rows="5" v-model="state.newTwootContent" />
<div class="create-twoot-type">
<lable for="twoot-type">
<strong>Twoot Type</strong>
</lable>
<select id="twoot-type" v-model="state.selectedTwootType">
<option
:value="option.value"
v-for="(option, index) in state.twootTypes"
:key="index"
>
{{ option.name }}
</option>
</select>
</div>
<button
type="submit"
:disabled="
newTwootContent.length === 0 ||
newTwootContent.length > 180 ||
newTwootType == 'draft'
"
>
Twoot
</button>
</form>
</template>
<script>
import { reactive, computed } from "vue";
export default {
name: "NewTwoot",
setup(_props, ctx) {
const state = reactive({
newTwootContent: "",
selectedTwootType: "instant",
twootTypes: [
{ value: "draft", name: "Draft" },
{ value: "instant", name: "Instant Twoot" },
],
});
const newTwootCharCount = computed(() => state.newTwootContent.length);
function createNewTwoot() {
ctx.emit("create-twoot", state.newTwootContent);
state.newTwootContent = "";
}
return {
state,
newTwootCharCount,
createNewTwoot,
};
},
};
</script>
I can see it on the elements tree but it show up as <newtwoot></newtwoot> as if it was empty.
I see two errors:
you only import TwootItem in the parent but not NewTwoot. This explains why it is not rendered properly.
You don't define the emit in the child component, look at my answer here:
vue 3 emit warning " Extraneous non-emits event listeners"
So importing the missing component import NewTwoot from "./NewTwoot.vue"; and adding it to the components should do the trick:
components: {
NewTwoot,
TwootItem,
}

Jest Testing Vue-Multiselect

I have a Vue application using Jest/Sinon for testing.
Currently having issues testing the vue-multiselect html element. I can't seem to be able to click on it and show the options. I want to watch some methods get executed as I click but since I can't seem to register a click on the darn thing I don't see any changes :(
Goal:
Click on multiselect drop down
Click on an option
Close dropdown which will submit selection
EditUser.vue
....
<div class="col2">
<form>
<label for="firstName">First Name: {{editUser.first_name}}</label>
<label for="lastname">Last Name: {{editUser.last_name}}</label>
<label for="email2">Email: {{editUser.id}}</label>
<label for="managerEmail">Manager Email: {{editUser.manager_email}}</label>
<label v-for="role in editUser.role" v-bind:key="role">Current Roles: {{role}}</label>
<label class="typo__label">
<strong>Select Roles OVERWRITES existing roles:</strong>
</label>
<div id="multiselectDiv" :class="{'invalid' : isInvalid}">
<multiselect
v-model="value"
:options="options"
:multiple="true"
:close-on-select="false"
:clear-on-select="false"
:preserve-search="true"
:allow-empty="false"
placeholder="Select All Applicable Roles"
:preselect-first="false"
#open="onTouch()"
#close="submitRoles(value)"
></multiselect>
<label class="typo__label form__label" v-show="isInvalid">Must have at least one value</label>
</div>
<button class="button" #click="removeRoles">Remove all roles</button>
</form>
</div>
....
<script>
import { mapState } from "vuex";
import Multiselect from "vue-multiselect";
const fb = require("../firebaseConfig.js");
import { usersCollection } from "../firebaseConfig";
export default {
computed: {
...mapState(["currentUser", "userProfile", "users", "editUser"]),
isInvalid() {
return this.isTouched && this.value.length === 0;
}
},
methods: {
onTouch() {
this.isTouched = true;
},
submitRoles(value) {
fb.usersCollection
.doc(this.editUser.id)
.update({
role: value
})
.catch(err => {
console.log(err);
});
this.$router.push("/dashboard");
},
removeRoles() {
fb.usersCollection
.doc(this.editUser.id)
.update({
role: []
})
.catch(err => {
console.log(err);
});
this.$router.push("/dashboard");
}
},
components: { Multiselect },
data() {
return {
value: [],
options: ["admin", "sales", "auditor"],
isTouched: false
};
}
};
</script>
editUserTest.spec.js
test('OnTouch method triggers on open of select menu', () => {
const wrapper = mount(EditUser, {
store,
localVue,
propsData: {
options: ["admin", "sales", "auditor"],
},
computed: {
editUser() {
return {
first_name: 'Bob',
last_name: 'Calamezo',
id: 'bob#email.com',
manager_email: 'someManager#email.com',
role: ['admin', 'sales'],
};
},
},
});
expect(wrapper.vm.$data.isTouched).toBe(false);
expect(wrapper.find('#multiselectDiv').exists()).toBe(true);
const selectIt = wrapper.find('#multiselectDiv').element;
selectIt.dispatchEvent(new Event('click'));
console.log(wrapper.find('.col2').html());
// expect(wrapper.vm.$data.isTouched).toBe(true);
});
Any help would be greatly appreciated!
Thanks!
What worked for me was this:
import { Multiselect } from 'vue-multiselect';
const multiselect = wrapper.findComponent(Multiselect);
const input = multiselect.find("input");
input.setValue("substring of a label");
input.trigger("keydown.enter");
Critically input.setValue is important if you want to find something in a list, rather than knowing its fixed offset in advance.
I got it to work with this:
import { Multiselect } from 'vue-multiselect';
const multiselect = wrapper.findComponent(Multiselect);
await multiselect.trigger('focus');
await multiselect.trigger('click');
Did you try it with:
let multiselect = wrapper.find('#multiselectDiv');
multiselect.vm.$emit('open');

Clear input VUE component data from parent

I'm a newbie of Vue, and I'm trying to simply clear the data of input component once I've submitted, but it seems I'm missing something, because since it's parent data is cleared, I still see the filled value of the input component.
Here is a living example.
I've set to the input child component v-model="title" from it's parent wrapper. Once I submit the data to the parent, I call addItem and in the end, I supposed to clear the data model just by clear it this.title = '', but I probably do something wrong on how to bind data from parent to child.
And above the code, starting from the parent component:
<template>
<form #submit="addItem" class="todo-insert">
<input-item
icon="create"
name="title"
placeholder="Add a ToVue item..."
v-model="title"
/>
<button-item tone="confirm" class="todo-insert__action">
Aggiungi
</button-item>
</form>
</template>
<script>
import ButtonItem from '#vue/Form/ButtonItem/ButtonItem.vue'
import InputItem from '#vue/Form/InputItem/InputItem.vue'
import uuid from 'uuid'
export default {
name: 'TodoInsert',
components: {
ButtonItem,
InputItem
},
data () {
return {
title: ''
}
},
methods: {
addItem (e) {
e.preventDefault()
const todo = {
id: uuid.v4(),
isComplete: false,
title: this.title
}
this.$emit('add-todo', todo)
this.title = ''
}
}
}
</script>
<style lang="scss" scoped src="./TodoList.scss"></style>
This is the child input component:
<template lang="html">
<label class="input">
<div v-if="label" class="input__label text-sans text-sans--label">
{{ label }}
</div>
<div class="input__row">
<input
:autocomplete="autocomplete"
:class="[hasPlaceholderLabel, isDirty]"
:name="name"
:placeholder="placeholder"
class="input__field"
type="text"
v-on:input="updateValue($event.target.value)"
v-on:blur="updateValue($event.target.value)"
>
<div v-if="placeholderLabel" class="input__placeholder text-sans text-sans--placeholder">
{{ placeholderLabel }}
</div>
<div v-if="icon" class="input__icon-area">
<icon-item
:name="icon"
/>
</div>
</div>
</label>
</template>
<script>
import IconItem from '../../IconItem/IconItem.vue'
export default {
name: 'InputItem',
props: {
autocomplete: {
type: String,
default: 'off'
},
icon: String,
label: String,
name: {
type: String,
default: 'input-text'
},
placeholder: String,
placeholderLabel: String
},
computed: {
hasPlaceholderLabel () {
return this.placeholderLabel ? 'input__field--placeholder-label' : ''
},
isDirty () {
// return this.$attrs.value ? 'input__field--dirty' : ''
return 'input__field--dirty'
}
},
methods: {
updateValue: function (value) {
this.$emit('input', value)
}
},
components: {
IconItem
}
}
</script>
<style lang="scss" src="./InputItem.scss"></style>
What am I missing?
Your child component is bound unidirectionally. It means that it can change the value, but does not receive any update from the parent component. To receive updates, you need to receive the property value in your child:
props: {
value: String
}
Then, you need to pass the value received to the input :
<input
:value="value"
:autocomplete="autocomplete"
:class="[hasPlaceholderLabel, isDirty]"
:name="name"
:placeholder="placeholder"
class="input__field"
type="text"
v-on:input="updateValue($event.target.value)"
v-on:blur="updateValue($event.target.value)"
>
Now the input should update when the parent component changes the value

ReactJS application passing state to multiple pages

I am developing a financial application in ReactJS. The application will be making use of a custom web API to retrieve data from a a MS SQL database. The initial landing page of the application requires the user to log in using his/her user ID and password. Once the user has logged in successfully, the menu options are provided to the user (ie: review balance, transfer between accounts, pay bills, etc).
In my design, each menu function will be a separate component in its own src/screens member. My directory structure looks like this:
The app launches and executes the src/screens/login.js file and allows the user to log in. Once the user logs in, the state contains the user ID and password, a user ID and a 4 digit reference code.
If I were to create a src/screens/account_balance.js page, how would I get the state from src/screens/index.js into the state of src/screens/account_balance.js? At the same time, when I create my src/screens/transfer_balance.js page, how would I get the state from src/screens/index.js into the state of src/screens/transfer_balance.js?
This is what my current login.js code looks like:
import React from 'react';
import '../styles/app.css';
//think of react components as functions
class login extends React.Component {
constructor(props) {
super(props);
this.state = {
passData: {
passFamilyID: '',
passPlanID: '',
passMemberID: '',
passPIN: ''
},
login: {
errorMessage: '',
errorCSS: 'visibility:hidden',
buttonText: 'Log In'
},
userID: {
valid: true,
value: '',
label: 'User ID',
length: 0,
css: 'input-group-text text-black input-size-200'
},
password: {
valid: true,
value: '',
label: 'Password',
length: 0,
css: 'input-group-text text-black input-size-200'
},
}
this.verifyLogin = this.verifyLogin.bind(this);
}
verifyLogin () {
let currentComponent = this;
var validData = true;
var mqResponse = '';
var localLogin = {
errorMessage: '',
errorCSS: 'visibility:hidden',
buttonText: 'Log In'
}
var localUserID = {
valid: true,
value: '',
label: 'User ID',
length: 0,
css: 'input-group-text text-black input-size-200'
}
var localPassword = {
valid: true,
value: '',
label: 'Password',
length: 0,
css: 'input-group-text text-black input-size-200'
}
localUserID.value = document.getElementById("txtUserID").value;
localPassword.value = document.getElementById("txtPassword").value;
if (localUserID.value.length < 3) {
validData = false;
localUserID.valid = false;
localUserID.css = "input-group-text text-danger input-size-200";
localLogin.errorMessage = "Invaid User ID length";
localLogin.errorCSS = "text-danger";
}
else {
localUserID.css = 'input-group-text text-black input-size-200';
}
if (localPassword.value.length >= 5) {
localPassword.css = 'input-group-text text-black input-size-200';
} else {
validData = false;
localPassword.valid = false;
localPassword.css = "input-group-text text-danger input-size-200";
localLogin.errorCSS = "text-danger";
if (localLogin.errorMessage == '') {
localLogin.errorMessage = "Invalid Password length";
} else {
localLogin.errorMessage = "Invalid User ID and Password length";
}
}
if (validData == false) {
currentComponent.setState({ userID:localUserID, password:localPassword, login: localLogin });
} else {
localLogin.buttonText = "Please wait.....";
currentComponent.setState({ userID:localUserID, password:localPassword, login: localLogin });
var templocalUserID = document.getElementById("txtUserID").value + " ";
var templocalPassword = document.getElementById("txtPassword").value + " ";
var mqUserID= templocalUserID.substring(0,40);
var mqPassword = templocalPassword.substring(0,10);
var MQMessage = "6007sP0001????DEMI0000000000 INTERNET/093000050" + mqUserID + mqPassword;
var mqResponse = "";
var mqErrorCode = 0;
MQMessage = encodeURI(MQMessage);
let url = "http://localhost:12976/api/Homepage?mqRequest=" + MQMessage;
const options = { method: 'GET' };
fetch(url, options)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
if (myJson == undefined)
{
console.log("fetch failed");
}
else
{
//inspect the data that the WebAPI returned
mqResponse = myJson[0].return_response;
mqErrorCode = myJson[0].return_code;
if (mqErrorCode > 0) {
localLogin.errorMessage = "We are having a problem connecting to our service. Please try again at a later time.";
localLogin.css = "input-group-text text-danger input-size-200";
localLogin.errorCSS = "text-danger";
currentComponent.setState({ userID:localUserID, password:localPassword, login:localLogin })
} else {
var mqResponseCode = mqResponse.substr(0,3);
if (mqResponseCode > 0) {
localLogin.errorMessage = "Incorrect UserID/Password.";
localLogin.css = "input-group-text text-danger input-size-200";
localLogin.errorCSS = "text-danger";
currentComponent.setState({ userID:localUserID, password:localPassword, login:localLogin })
} else {
var localData = {
familyID: ' ',
planID: mqResponse.substr(27,4),
memberID: mqResponse.substr(13,10),
PIN: mqResponse.substr(23,4)
}
currentComponent.setState({ passData:localData })
location.href = "/account_balance";
}
}
}
});
}
}
render() {
return (
<div className="App">
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<a className="navbar-brand" href="#">Access your 401(k)</a>
</nav>
<div className="d-flex flex-wrap justify-content-center align-items-center align-content-center">
<div className="container">
<div className="row">
<div>
<form>
<p className="h4 text-center py-4">Please Log In</p>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className={this.state.userID.css}>{this.state.userID.label}</span>
</div>
<input id="txtUserID" type="text" className="form-control" />
</div>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className={this.state.password.css}>{this.state.password.label}</span>
</div>
<input id="txtPassword" type="current-password" className="form-control" />
</div>
<div className="text-center py-4 mt-3">
<button type="button" className="btn btn-primary" onClick={() => {
this.verifyLogin();
}}>{this.state.login.buttonText}</button>
</div>
<div className={this.state.login.errorCSS}>
<p className="h4 text-center">{this.state.login.errorMessage}</p>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
);
<main details={this.state.passData} />
}
}
export default login
When I execute the application, I enter a user ID and Password. The data is retrieved and I pick up 4 pieces of data from the returned string. I then push those 4 pieces of data into the state. Then, I execute location.href='/account_balance'.
This redirects to the account_balance.js page. This is the code in my account_balance.js:
import React from 'react';
import '../styles/app.css';
//think of react components as functions
class account_balance extends React.Component {
constructor(props) {
super(props);
state = {
passData: {
passFamilyID: this.props.details.passFamilyID,
passPlanID: this.props.details.passPlanID,
passMemberID: this.props.details.passMemberID,
passPIN: this.props.details.passPIN
}
}
}
componentWillUpdate() {
console.log("passedData: ", state.passedData);
MQMessage = "6000" + "sP0000" + "????" + state.passData.passPlanID + state.passData.passMemberID + state.passData.FamilyID + "INTERNET/";
mqResponse = "";
mqErrorCode = 0;
MQMessage = encodeURI(MQMessage);
url = "http://localhost:12976/api/Homepage?mqRequest=" + MQMessage;
fetch(url, options)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
if (myJson == undefined)
{
console.log("fetch failed");
}
else
{
//inspect the data that the WebAPI returned
mqResponse = myJson[0].return_response;
mqErrorCode = myJson[0].return_code;
console.log("mqErrorCode: ", mqErrorCode);
console.log("mqResponse: ", mqResponse);
}
});
}
render() {
return (
<div className="App">
<div>
<label>output from account_balance.js</label>
</div>
<div>
<label>{this.state.passData.passFamilyID}</label>
</div>
<div>
<label>{this.state.passData.passPlanID}</label>
</div>
<div>
<label>{this.state.passData.passMemberID}</label>
</div>
<div>
<label>{this.state.passData.passPIN}</label>
</div>
</div>
)
}
}
export default account_balance
When the account_balance.js page loads, I see this in the console.log():
Uncaught TypeError: Cannot read property 'passFamilyID' of undefined
at new main (main.js:12)
When i click on the link to the line generating the error, this is what I see:
you can use props to share the state data from one component to another, or you can use redux as global state.
For example your index.js state looks like:
state = {
name: 'sameer',
}
render() {
return (
<Accountbal details={this.state.name} />
)
}
Now your Account bal component code looks like account_bal.js
constructor(props) {
super(props);
state = {
name: this.props.details, // here you can access the name from index.js
}
}
render() {
return (
)
}
I followed the suggestion by Mohamed Sameer and incorporated the code. After trial and error, and additional research on the web, I found out a command. I removed my location.href which I was using to redirect to the account_balance.js and added a state variable Boolean to let me know if I want to redirect on the render.
In the render, I placed this code:
if (this.state.passData.redirect === true) {
return (
<Redirect to={{
pathname: "/account_balance",
state: {
familyID: this.state.passData.passFamilyID,
planID: this.state.passData.passPlanID,
memberID: this.state.passData.memberID,
PIN: this.state.passData.PIN
}
}}/>
)
}
This passes the state variables from the current page to the account_balance page.
In the account_balance.js, I put in this line of code:
console.log("props: ", this.props.location.state);
Just to test the functionality. When the account_balance,js loads, I looked at the console.log() and I saw the values I passed.

Categories