2
votes

I am trying to set up a vue app that makes a request to a backend and then displays the result on the page. I cooked up this example

new Vue({
    data: {
        message: '{}'
    },
    el: '.login-app',
});

Vue.component('message-section', {
    template: '<div>Message Section</div>'
});

Vue.component('login-component', {
    template: '<div><button v-on:click="login(\'[email protected]\', \'passwd\')">Login</button></div>',
    methods: {
        login: function (username, password) {
            axios.post("http://192.168.1.10:8080/login", {username: username, password: password})
                .then(response => {this.message = response.data})
        }
    }
});

and an index like:

<!DOCTYPE html>

<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Vue Test</title>
  </head>
  <body>
    <div class="login-app">
      {{ message }}
      <message-section></message-section>
      <login-component></login-component>
    </div>
    <script src="/static/testvue.bundle.js"></script>
  </body>
</html>

The idea being a simple app that should send a username/password and get back something like "success" or whatever that it can display. But I am completely unfamiliar with vue and javascript so I am getting stuck. I am not sure how to make the response show up anywhere. I have a {{ message }} in there but it doesn't do anything. All I see is the {} from the "message" attribute of the Vue object getting rendered in I guess. And those user/pass is hard coded... I am not sure how to make it work with a form field.

I can see the data getting sent to the backend though so I know that's working...

Additionally, how can you structure a Vue project so it's broken into multiple "modules" or whatever?

Edit:

If I change it so there's only one component like so:

new Vue({
    data: {
        message: '{}'
    },
    el: '.login-app',
    methods: {
        login: function (username, password) {
            axios.post("http://192.168.91.30:8080/login", {username: username, password: password})
                .then(response => {this.message = response.data})
        }
    }

})

and

<div class="login-app">
  {{ message }}
  <button v-on:click="login(\'[email protected]\', \'passwd\')">Login</button>
</div>

Then nothing renders at all... This should have put them inside the same container or whatever, right?

2
The core issue here is message is a data property declared in your root Vue, but you are attempting to set it from a component that doesn't have direct access to it. Typically, if you want to change the value from a child component, you will need to $emit the value to the parent. - Bert
I have no idea what that means... but I edited my question a bit - MichaelB

2 Answers

4
votes

Here is your edited code working.

console.clear()

new Vue({
  data: {
    message: '{}'
  },
  el: '#login-app',
  methods: {
    login: function(username, password) {
      axios.post("https://httpbin.org/post", {username, password})
        .then(response => this.message = response.data.json)
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.17.1/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.min.js"></script>

<div id="login-app">
  {{ message }}
  <button v-on:click="login('[email protected]', 'passwd')">Login</button>
</div>

Here it is working from a component.

console.clear()

Vue.component('login-component', {
  template: `
    <div>
      <button v-on:click="login('[email protected]', 'passwd')">Login</button>
    </div>`,
  methods: {
    login: function(username, password) {
      axios.post("https://httpbin.org/post", {username, password})
        .then(response => this.$emit('login-success', response.data.json))
    }
  }
});

new Vue({
  data: {
    message: '{}'
  },
  el: '#login-app',
  methods: {
    onSuccess(message) { this.message = message }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.17.1/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.min.js"></script>

<div id="login-app">
  {{ message }}
  <login-component @login-success="onSuccess"></login-component>
</div>

In this second example, note that message is a data property of the parent; the root Vue. The login-component does not have direct access to message. That being the case, if the ajax call is made in the component, in order to set message the value has to be emitted from the component. The code does that by emitting the custom event, login-success with the success value passed as a parameter. The parent listens for that event with the following syntax:

<login-component @login-success="onSuccess"></login-component>
1
votes

The problem is your component login-component doesn't have access to the message property, which belongs to the root Vue app.

One way to fix this is simply put the message to the component instead:

Vue.component('login-component', {
  template: '<div><button v-on:click="login(\'[email protected]\', \'passwd\')">Login</button></div>',
  data() { 
    return { message: '' }
  },
  methods: {
    login: function (username, password) {
      axios.post("http://192.168.1.10:8080/login", {username: username, password: password})
        .then(response => {this.message = response.data})
      }
    }
});

But if message is not a property that you login-component to have solely access to, you may have to consider Vuex or emitting custom events (this and this).