<!DOCTYPE html>
<html>
<head>
<link data-require="bootstrap@*" data-semver="3.3.2" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
<script data-require="jquery@2.1.3" data-semver="2.1.3" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
<script data-require="angular.js@*" data-semver="1.4.0-beta.5" src="https://code.angularjs.org/1.4.0-beta.5/angular.js"></script>
<script data-require="bootstrap@*" data-semver="3.3.2" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script data-require="angular-animate@*" data-semver="1.4.0-beta.5" src="https://code.angularjs.org/1.4.0-beta.5/angular-animate.js"></script>
<script data-require="mathjs@*" data-semver="0.27.0" src="http://cdnjs.cloudflare.com/ajax/libs/mathjs/0.27.0/math.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="myApp" ng-controller="MainCtrl as main">
<p></p>
<table class="exprs">
<tbody>
<tr class="animate-repeat" ng-repeat="expr in main.exprs">
<td>
<input ng-model="expr.key" class="badge-input" />
<button class="btn btn-link btn-xs" ng-click="remove(expr)">x</button>
</td>
<td>
<input ng-model="expr.expr" class="form-control input-sm" />
</td>
<td>{{expr.value}}</td>
</tr>
<tr>
<td>
<button class="btn btn-xs btn-primary add-button" ng-click="main.exprs.push({})">(+)</button>
</td>
</tr>
</tbody>
</table>
</body>
</html>
// Code goes here
angular.module('myApp', ['ngAnimate'])
.controller('MainCtrl', function($scope, $parse) {
var main = this;
main.exprs = [
{ key: 'x', expr: '5' },
{ key: 'y', expr: 'range(0,x)' },
{ key: 'z', expr: 'round(log(y))' },
{ key: 't', expr: 'y[x-1]' }
];
var locals = {};
var ctx = math.create({
matrix: 'array' // Choose 'matrix' (default) or 'array'
});
function digest() {
var newValues = {};
main.exprs.forEach(function(v) {
var getter = $parse(''+v.expr);
try {
v.value = newValues[v.key] = getter(ctx,locals);
} catch(err) {
v.value = newValues[v.key] = null;
}
});
locals = newValues;
}
$scope.$watch('main.exprs', digest, true);
$scope.$watch(function() { return locals; }, digest, true);
$scope.remove = function(d) {
var i = main.exprs.indexOf(d);
if (i > -1) {
main.exprs.splice(i,1);
}
}
});
/* Styles go here */
.exprs {
width: 100%;
text-align: center;
}
.exprs tr {
height: 32px;
}
.exprs td {
width: 33%;
max-width: 300px;
text-align: center;
overflow-x: auto;
}
.badge-input {
background-color: lightblue;
border: none;
border-radius: 10px;
padding-left: 10px;
width: auto;
}
.add-button {
margin-left: 10px;
background-color: lightblue;
border-color: lightblue;
}
.animate-repeat {
}
.animate-repeat.ng-move,
.animate-repeat.ng-enter,
.animate-repeat.ng-leave {
-webkit-transition:all linear 0.3s;
transition:all linear 0.3s;
}
.animate-repeat.ng-leave.ng-leave-active,
.animate-repeat.ng-move,
.animate-repeat.ng-enter {
opacity:0;
max-height:0;
}
.animate-repeat.ng-leave,
.animate-repeat.ng-move.ng-move-active,
.animate-repeat.ng-enter.ng-enter-active {
opacity:1;
max-height:40px;
}