JSFiddle - React, Tailwind, and code Playground

by andreas_karz

HTML

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.2/angular.min.js"></script>
<div id="demo.module.mBoard" ng-controller="mBoardCtrl as mb">
  <h2 ng-click="mb.addHost()">Monitoring Board <span class="small">{{mb.totalErrors}}</span></h2>
  <widget class="widget" ng-repeat="host in mb.data | orderBy: 'host'" host="{{host.host}}" error="host.error"></widget>
  <hr />
  <input type="text" ng-model="mb.data[0].host">
  <pre>{{mb.data|json}}</pre>
  <!-- https://docs.angularjs.org/api/ng/service/$templateCache -->
  <script type="text/ng-template" id="template.html">
    <div class="widget">
      <input type="text" class="label" ng-model="widget.host">
      <input type="text" class="error" ng-model="widget.error"> 
      <button type="button" ng-click="widget.decrement();">-</button>
      <button type="button" ng-click="widget.increment();">+</button>
      {{mb.totalErrors}} <!-- Funktioniert nur, wenn isolate:false -->
    </div>
  </script>
</div>

CSS

.widget{
  display: inline-block;
  border:1px solid silver;
  width:200px;
  height:110px;
  margin-right:20px;
  margin-bottom:20px;
  background-color:#383737;
  color:#FFF;
}

.widget input[type="text"]{
  background-color:#383737;
  color:#FFF;
  border:0;
  padding:0;
}

.widget input[type="text"].label{
  margin:0;
  padding:0;
  text-align: center;
  width: 186px;
  padding:7px;
  font-size: 1.1rem;
  border-bottom:1px dashed silver;
  margin-bottom: 20px;
}

.widget input[type="text"].error{
  width: 30px;
  border:1px solid grey;
  margin-left: 20px;
}

span.small{
  font-size: 1rem;
}

pre{
  font-size:10px;
}

body{
  margin-left:20px;
}

JavaScript

angular
	.module('mBoard', [])
	.component('widget', {
    isolate: true,
    bindings: {
      error: '=', /* two way binding */
      host: '@' /* one way binding */
    },
    controller: function () {
      function increment() {
        this.error++;
      }
      function decrement() {
        this.error--;
      }
      this.increment = increment;
      this.decrement = decrement;
    },
    templateUrl: 'template.html'
  })
	.controller('mBoardCtrl', function mBoardCtrl($interval, $scope) {
		this.data = [];
		this.totalErrors = 0;
    /* Simulierter AJAX-Request */
      var getData = function(mBoardCtrl){
        mBoardCtrl.data = window.data;
        var min = 1;
        var max = 20;
        var x = Math.floor(Math.random() * (max - min)) + min;
        mBoardCtrl.data[0].error=x;
      }
      getData(this); // Init
      /* https://docs.angularjs.org/api/ng/service/$interval */
      $interval(getData, 10000, 0, true, this);	// Interval
		/* Trigger, wenn sich Daten ändern */
    	/* https://docs.angularjs.org/api/ng/type/$rootScope.Scope */
      $scope.$watch(angular.bind(this, function () {
        return this;
      }), function (newVal, oldVal) {
          newVal.totalErrors = 0;
          for (x in newVal.data) {
            newVal.totalErrors += parseInt(newVal.data[x].error);
          }
      }, true);
		/* Neuen Host hinzufügen */
      this.addHost = function(){
        var newHost = {
          'host': 'CRM LoadBalancer 2',
          'error': 3
        }
        this.data.push(newHost);
      }
	})
;

window.data = [
  {
    'host': 'CRM Main Server 1',
    'error':0
  },
  {
    'host': 'CRM LoadBalancer 1',
    'replicator':'CRM Main Server 1',
    'error': 2
  }
];

/* https://docs.angularjs.org/guide/bootstrap */
angular.bootstrap(document.getElementById("demo.module.mBoard"), ['mBoard']);