JSFiddle - React, Tailwind, and code Playground

HTML

<script src="http://d1l4stvdmqmdzl.cloudfront.net/4.0.0-rc2/mongoose.min.js"></script>
<div ng-app="mongooseExample">  
    <div ng-controller="TestController">
        <h2>Add New Stock</h2>
        <h4>Symbol</h4>
        <select ng-model="newStock.symbol" ng-options="symbol for symbol in VALID_SYMBOLS">
        </select>
        <div ng-if="validationError.errors['symbol'].kind" class="error">
            {{validationError.errors['symbol'].message}}
        </div>
        <h4>Price</h4>
        <select ng-model="newStock.price.currency" ng-options="currency for currency in CURRENCIES">
        </select>
        <input type="number" ng-model="newStock.price.price" />
        <div ng-if="validationError.errors['price.price'].kind" class="error">
            {{validationError.errors['price.price'].message}}
        </div>
        <div ng-if="validationError.errors['price.currency'].kind" class="error">
            {{validationError.errors['price.currency'].message}}
        </div>
        <h4>Quantity</h4>
        <input type="number" ng-model="newStock.quantity" />
        <div ng-if="validationError.errors['quantity'].kind" class="error">
            {{validationError.errors['quantity'].message}}
        </div>
        <br />
        <input type="submit" ng-click="saveStock()" value="Add Stock" />
        <hr />
        <h2>List of Stocks</h2>
        <div ng-repeat="stock in stockList.stocks">
            {{stock.symbol}} @ {{stock.displayPrice}}
        </div>
    </div>
</div>

CSS

.error {
    color: red;
}

JavaScript

var VALID_SYMBOLS = ["APPL", "GOOG", "MSFT"];
var CURRENCIES = ["USD", "EUR"];

var stockSchema = new mongoose.Schema({
  symbol: {
    type: String,
    required: true,
    enum: VALID_SYMBOLS
  },
  price: {
    price: {
      type: Number,
      required: true,
      min: 0
    },
    currency : {
      type: String,
      required: true,
      enum: CURRENCIES
    }
  },
  quantity : {
    type: Number,
    required: true,
    min: 0
  }
});

stockSchema.virtual('displayPrice').get(function() {
  return this.price.currency + ' ' + this.price.price;
});

var stockListSchema = new mongoose.Schema({
  stocks: [stockSchema]
});

var mongooseExample = angular.module('mongooseExample', []);

mongooseExample.controller('TestController', function($scope) {
    $scope.stockList = new mongoose.Document({}, stockListSchema);
    $scope.validationError = null;
    
    $scope.resetInput = function() {
        $scope.newStock = new mongoose.Document({}, stockSchema);
    };
    $scope.resetInput();
    $scope.VALID_SYMBOLS = VALID_SYMBOLS;
    $scope.CURRENCIES = CURRENCIES;
    
    $scope.saveStock = function() {
        $scope.validationError = null;
        $scope.newStock.validate(function(err) {
            if (err) {
                $scope.validationError = err;
                console.log(JSON.stringify(err.errors, null, '  '));
                return $scope.$apply();
            }
            $scope.stockList.stocks.push($scope.newStock);
            $scope.resetInput();
            $scope.$apply();
        });
    };
});