JSFiddle - React, Tailwind, and code Playground

HTML

<div ng-app="nameDog" ng-controller="NamingCtrl as Naming">
<div class="loading" ng-show="Naming.isLoading"><!-- loading icon -->
  <div class="spinner">
      <div class="rect1"></div>
      <div class="rect2"></div>
      <div class="rect3"></div>
      <div class="rect4"></div>
      <div class="rect5"></div>
  </div>
</div>
 <div><!-- main view -->
    <h2>{{Naming.dog.name}} 的小檔案</h2>
    <image src="https://dl.dropboxusercontent.com/u/7141512/S__4538465.jpg" width="200px" height="300px"></image>
    <div>性別: {{Naming.dog.sex}}</div>
    <div>最喜歡的食物: {{Naming.dog.food}}</div>
    <input type="text" placeholder="我要換名字..." ng-model="Naming.newName">
    <button ng-click="Naming.updateName()">換!</button>
   </div>
</div>

CSS

.loading {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: #ccc;
    opacity: 0.5;
}
/** copy from http://tobiasahlin.com/spinkit */
.spinner {
  margin: 100px auto;
  width: 50px;
  height: 30px;
  text-align: center;
  font-size: 10px;
}

.spinner > div {
  background-color: #fff;
  height: 100%;
  width: 6px;
  display: inline-block;
  
  -webkit-animation: stretchdelay 1.2s infinite ease-in-out;
  animation: stretchdelay 1.2s infinite ease-in-out;
}

.spinner .rect2 {
  -webkit-animation-delay: -1.1s;
  animation-delay: -1.1s;
}

.spinner .rect3 {
  -webkit-animation-delay: -1.0s;
  animation-delay: -1.0s;
}

.spinner .rect4 {
  -webkit-animation-delay: -0.9s;
  animation-delay: -0.9s;
}

.spinner .rect5 {
  -webkit-animation-delay: -0.8s;
  animation-delay: -0.8s;
}

@-webkit-keyframes stretchdelay {
  0%, 40%, 100% { -webkit-transform: scaleY(0.4) }  
  20% { -webkit-transform: scaleY(1.0) }
}

@keyframes stretchdelay {
  0%, 40%, 100% { 
    transform: scaleY(0.4);
    -webkit-transform: scaleY(0.4);
  }  20% { 
    transform: scaleY(1.0);
    -webkit-transform: scaleY(1.0);
  }
}

JavaScript

var app = angular.module('nameDog', []);
app.controller('NamingCtrl', function ($scope, dogService) {
    var naming = this;
    // 控制 loading 顯示
    naming.isLoading = true;   
    naming.newName = '';

    // 取得狗狗資料
    dogService.getDogInfo().then(function (data) {
        naming.dog = data;
        naming.isLoading = false;
    }); 
    
    naming.updateName = function () {
        if (naming.newName) {
            naming.isLoading = true;
            dogService.updateDogName(naming.newName).then(function (data){
                naming.dog.name = data.name;
                naming.isLoading = false;
            });
        }
    }
   
});
app.service('dogService', function ($q, $timeout){
    var service = this,
        // 沒有真實後端, 先把資料寫死
        dog = {
            name: 'gucci',
            sex: 'F',
            food: '蘋果麥片小餅乾'
        };
    
    this.getDogInfo = function () {
        var d = $q.defer();
        $timeout(function () {
            d.resolve(dog);
        }, 300);
        return d.promise;
    }
    
    this.updateDogName = function (newName) {
        var d = $q.defer();     
        // 假資料逼真一點, 用 $timeout 等一下在回傳
        $timeout(function () {
            dog.name = newName;
            d.resolve(dog);
        }, 2000);
        return d.promise;
    }
});