Sean
Sean

Reputation: 670

Vuejs Passing dynamic data from parent to child component

I've got a view and a component. I'm trying to do auth here.

As a user, I input username and password, click login. This emits the information to the parent component, which makes a fetch request to API gateway in AWS. This fetch response has a header X-Session-Id that I'm interested in.

I've got the emit bit working fine.

However, I'm unable to pass the header value back to the component, and I'm unable to set new_password_required to true, which would add a new input field for a new password, as well as replace the login button with a reset password button.

I feel like I need to do this with props, but I'm unable to successfully pass the values from parent to child.

Also, should the reset password bit have its own component?

Here's my code below. This is my first frontend, so I'm not familiar with how I am supposed to share it (e.g. with a playground). Also, I'm trying to stick to vanilla vue for now since I'm learning (I've only get vue-router installed I think)

parent:

<template>
  <div id="app" class="small-container">
    <login-form @login:user="loginUser($event)" />
  </div>
</template>

<script>
import LoginForm from "@/components/LoginForm.vue";

export default {
  name: "Login",
  components: {
    LoginForm
  },
  data() {
    return {
      session_id: String,
      new_password_required: Boolean
    };
  },
  methods: {
    async loginUser(loginEvent) {
      try {
        const response = await fetch(
          process.env.VUE_APP_API_GATEWAY_ENDPOINT + "/login/user",
          {
            method: "POST",
            body: JSON.stringify(loginEvent)
          }
        );
        const data = await response.json();
        console.log(data);
        if (data.headers["X-Session-Id"] != null) {
          this.session_id = data.headers["X-Session-Id"];
          this.new_password_required = true;
        }
      } catch (error) {
        console.error(error);
      }
    },
    async resetPassword(resetPasswordEvent) {
      try {
        const response = await fetch(
          process.env.VUE_APP_API_GATEWAY_ENDPOINT + "/reset/user/password",
          {
            method: "POST",
            body: JSON.stringify(resetPasswordEvent)
          }
        );
        const data = await response.json();
        console.log(data);
      } catch (error) {
        console.error(error);
      }
    }
  }
};
</script>

Component:

<template>
  <div id="login-form">
    <h1>Serverless App</h1>
    <form>
      <label for="email_address">Email Address:</label><br />
      <input
        v-model="login_details.email_address"
        type="text"
        id="email_address"
        name="email_address"
      /><br />
      <label for="password">Password:</label><br />
      <input
        v-model="login_details.password"
        type="password"
        id="password"
        name="password"
      />
      <label v-if="new_password_required" for="new_password"
        >New Password:</label
      ><br />
      <input
        v-if="new_password_required"
        v-model="login_details.new_password"
        type="password"
        id="new_password"
        name="new_password"
      />
    </form>
    <button v-if="!new_password_required" @click="loginUser($event)">
      Login
    </button>
    <button v-if="new_password_required" @click="resetPassword($event)">
      Reset Password
    </button>
  </div>
</template>

<script>
export default {
  name: "LoginForm",
  props: {
    session_id: String,
    new_password_required: {
      type: Boolean,
      default: () => false
    }
  },
  data() {
    return {
      login_details: {
        email_address: "",
        password: "",
        new_password: ""
      }
    };
  },

  methods: {
    loginUser() {
      console.log("testing loginUser...");
      const loginEvent = {
        email_address: this.login_details.email_address,
        password: this.login_details.password
      };
      this.$emit("login:user", loginEvent);
    },

    resetPassword() {
      console.log("testing resetPassword...");
      const resetPasswordEvent = {
        email_address: this.login_details.email_address,
        password: this.login_details.password,
        new_password: this.login_details.new_password,
        session_id: this.login_details.sessionId
      };
      this.$emit("reset:Password", resetPasswordEvent);
    }
  }
};
</script>

Upvotes: 1

Views: 6749

Answers (2)

jaffa
jaffa

Reputation: 136

Your child component looks good, however, you need to pass the props through in the parent component as shown here:

<login-form @login:user="loginUser($event)" :session-id="xidhere"
    :new-password-required="newPasswordRequired"/>

As these values are updated in the parent component, the child component should be updated.

As a note, name your props using camel case, and then use kebab-case in your HTML.

So your login-form props should be updated to:

  props: {
    sessionId: String,
    newPasswordRequired: {
      type: Boolean,
      default: () => false
    }
  },

Also, as you are emitting the event to parent, there may be no need to send the session id to the child, just add this to your api call before you send it.

Upvotes: 2

Sean
Sean

Reputation: 670

Figured it out. I created a new child component for resetting password. Perhaps it can be dry'd up a bit? I'm new at this. Happy for any pointers :)

PARENT

<template>
  <div id="app" class="small-container">
    <login-form v-if="!new_password_required" @login:user="loginUser($event)" />
    <reset-password-form
      v-if="new_password_required"
      :session_id="session_id"
      @reset:password="resetPassword($event)"
    />
  </div>
</template>

<script>
import LoginForm from "@/components/LoginForm.vue";
import ResetPasswordForm from "@/components/ResetPasswordForm.vue";

export default {
  name: "Login",
  components: {
    LoginForm,
    ResetPasswordForm
  },
  data() {
    return {
      session_id: "",
      new_password_required: false
    };
  },
  methods: {
    async loginUser(loginEvent) {
      try {
        const response = await fetch(
          process.env.VUE_APP_API_GATEWAY_ENDPOINT + "/login/user",
          {
            method: "POST",
            body: JSON.stringify(loginEvent)
          }
        );
        const data = await response.json();
        console.log(data);
        if (data.headers["X-Session-Id"] != null) {
          this.session_id = data.headers["X-Session-Id"];
          this.new_password_required = true;
        }
      } catch (error) {
        console.error(error);
      }
    },

    async resetPassword(resetPasswordEvent) {
      try {
        const response = await fetch(
          process.env.VUE_APP_API_GATEWAY_ENDPOINT + "/reset/user/password",
          {
            method: "POST",
            body: JSON.stringify(resetPasswordEvent)
          }
        );
        const data = await response.json();
        console.log(data);
      } catch (error) {
        console.error(error);
      }
    }
  }
};
</script>

CHILD: login-form

<template>
  <div id="login-form">
    <h1>Serverless Release Dashboard</h1>
    <form>
      <label for="email_address">Email Address:</label><br />
      <input
        v-model="login_details.email_address"
        type="text"
        id="email_address"
        name="email_address"
      /><br />
      <label for="password">Password:</label><br />
      <input
        v-model="login_details.password"
        type="password"
        id="password"
        name="password"
      />
    </form>
    <button @click="loginUser($event)">
      Login
    </button>
  </div>
</template>

<script>
export default {
  name: "LoginForm",
  data() {
    return {
      login_details: {
        email_address: "",
        password: ""
      }
    };
  },

  methods: {
    loginUser() {
      console.log("testing loginUser...");
      const loginEvent = {
        email_address: this.login_details.email_address,
        password: this.login_details.password
      };
      this.$emit("login:user", loginEvent);
    }
  }
};
</script>

CHILD: reset-password-form

<template>
  <div id="reset-password-form">
    <h1>Serverless Release Dashboard</h1>
    <form>
      <label for="email_address">Email Address:</label><br />
      <input
        v-model="login_details.email_address"
        type="text"
        id="email_address"
        name="email_address"
      /><br />
      <label for="password">Password:</label><br />
      <input
        v-model="login_details.password"
        type="password"
        id="password"
        name="password"
      />
      <label for="new_password">New Password:</label><br />
      <input
        v-model="login_details.new_password"
        type="password"
        id="new_password"
        name="new_password"
      />
    </form>
    <button @click="resetPassword($event)">
      Reset Password
    </button>
  </div>
</template>

<script>
export default {
  name: "ResetPasswordForm",

  props: {
    email_address: String,
    password: String,
    session_id: String
  },

  data() {
    return {
      login_details: {
        email_address: "",
        password: "",
        new_password: "",
        session_id: ""
      }
    };
  },

  methods: {
    resetPassword() {
      console.log("testing resetPassword...");

      const loginEvent = {
        email_address: this.email_address,
        password: this.password,
        new_password: this.login_details.new_password,
        session_id: this.session_id
      };
      this.$emit("reset:password", loginEvent);
    }
  }
};
</script>

Upvotes: 0

Related Questions