jsFiddle echo axios demo

by Miro Hristov

HTML

<!-- Required Stylesheets -->
    <link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
    <link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.css" />

    <!-- Load polyfills to support older browsers -->
    <script src="https://polyfill.io/v3/polyfill.min.js?features=es2015%2CIntersectionObserver"></script>

    <!-- Required scripts -->
    <script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
    <script src="https://unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.min.js"></script>


    <!-- Our application root element -->
    <div id="app">
      <b-container>


        <div v-for="(post,index) in posts" :key="post.id" :class="{loading: loadingItems.indexOf(post) >= 0}">
          <b-card class="mb-2">
            <b-card-title>{{post.title}}</b-card-title>
            <b-card-text>
              {{post.body}}
            </b-card-text>

            <a href="#" @click.prevent="removeItem(post)" :class="{ loading: post.isLoading }" class="card-link">
              Remove
              <span v-show="post.isLoading" class="spinner"></span>
            </a>

          </b-card>
        </div>


      </b-container>
    </div>

CSS

.loading * {
        background: yellow;
      }
      @keyframes spinner {
        to {transform: rotate(360deg);}
      }
      
      .spinner{
        position:relative;
      }
      .spinner:before {
        content: '';
        box-sizing: border-box;
        position: absolute;
        top: 50%;
        left: 1em;
        width: 20px;
        height: 20px;
        margin-top: -10px;
        margin-left: -10px;
        border-radius: 50%;
        border: 2px solid #ccc;
        border-top-color: #000;
        animation: spinner .6s linear infinite;
      }

JavaScript

window.app = new Vue({
        el: '#app',
        data: {
          name: '',
          posts: [],
          loadingItems: [],
        },
        created() {
            this.fetchData(); 
        },        
        methods:{
            fetchData() {
                axios.get('https://jsonplaceholder.typicode.com/posts').then(response => {
                    this.posts = response.data.slice(0,20);

                });
            },
            removeItem(item) {
                
                var index = this.posts.indexOf(item);
                
                //var loadingIndex = this.loadingItems.push(item) - 1;
                //console.log(loadingIndex);
                
                item.isLoading = true;
                
                //Update vue array on the fly hack - https://vuejs.org/2016/02/06/common-gotchas/
                this.posts.splice(index, 1,item); 


                axios.post('/echo/json/', "json='{status:success}'&delay=2")
                .then(response => {
                    
                    this.posts.splice(index, 1);
                    
                    //this.loadingItems.splice(loadingIndex, 1);
                    //this.loadingItems.pop(item);
                    
                    //item.isLoading = false;
                    //this.posts.splice(index, 1,item); 
                });                
            }
        },
        computed: {
          showAlert() {
            return this.name.length > 4 ? true : false
          }
        }
      })