Vue and axios make request and display result

17,149

Solution 1

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>

Solution 2

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).

Share:
17,149

Related videos on Youtube

MichaelB
Author by

MichaelB

Updated on June 04, 2022

Comments

  • MichaelB
    MichaelB almost 2 years

    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?

    • Bert
      Bert over 6 years
      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.
    • MichaelB
      MichaelB over 6 years
      I have no idea what that means... but I edited my question a bit
  • MichaelB
    MichaelB over 6 years
    In the first example, all you seem to have changed from my "edited" thing is changing a .login-app to #login-app and also adding a .json to the response.data. What's the difference between the dot and the hash?
  • Bert
    Bert over 6 years
    @MichaelB You don't want to create a Vue on a class because there could be more than one element with that class. It's just a bad practice. #login-app is a CSS selector that chooses an element with the id of login-app. You can safely ignore my changes to the ajax call; those are only because there is no way to make a call to your server, so I updated the call to use a generic site that handles POSTs.
  • MichaelB
    MichaelB over 6 years
    So, in the second case, you're telling the parent to listen for an event called @login-success and when it hears that, run its own onSuccess method. Then you "emit" the login-success event from the child and the argument of whatever the ajax thing returned and they just get wired together.
  • Bert
    Bert over 6 years
    @MichaelB You got it.