Question

I'm creating a small calculator and it creates multiple values with binds. Is there a better way to do this? I feel like this is utter hackery. I'm new to Angular.

The calculator:

<div ng-app="App" ng-controller="CalculatorCtrl">
    <form action="javascript:;" id="calculator" class="form-inline">
        <fieldset class="grid grid-4">
            <div class="item">
                <input required type="number" 
                    ng-model="data.buy"
                    placeholder="Buy Price" 
                    maxlength="10"
                    tabindex="1" />
            </div>

            <div class="item">
                <input required type="number" 
                    ng-model="data.sell"
                    placeholder="Sell Price/target" 
                    maxlength="10"
                    tabindex="2" />
            </div>

            <div class="item">
                <input required type="number" 
                    ng-model="data.shares"
                    placeholder="Share Count" 
                    maxlength="10"
                    tabindex="3" />
            </div>

            <div class="item">
                <input required type="number" 
                    ng-model="data.fee"
                    placeholder="Commission Fee" 
                    maxlength="10"
                    tabindex="3" />
            </div>
        </fieldset>
    </form>

    <!-- Results -->
    <table class="table table-bordered table-striped table-hover">
        <tr>
            <th width="150">Total Profit</th>
            <td>{{ profit() | number:2 }}%</td>
        </tr>

        <tr>
            <th width="150">Net Gain</th>
            <td>{{ data.net = (data.soldFor - data.purchasedFor) | currency }}</td>
        </tr>

        <tr>
            <th width="150">Purchased For</th>
            <td>{{ data.purchasedFor = (data.buy * data.shares) + data.fee | currency }}</td>
        </tr>

        <tr>
            <th width="150">Sold For</th>
            <td>{{ data.soldFor = (data.sell * data.shares) - data.fee | currency }}</td>
        </tr>
    </table>
</div>

The JS (coffeescript) in question:

# Core Coffee
app = angular.module 'App', []
app.controller 'CalculatorCtrl', ['$scope', ($scope) ->
    $scope.profit = ->
        data = $scope.data
        return 0 unless data? and data.net? and data.purchasedFor? and data.soldFor?

        a = if data.soldFor > data.purchasedFor then data.soldFor else data.purchasedFor
        b = if a is data.soldFor then data.purchasedFor else data.soldFor

        res = if data.net >= 1 then '+' else '-'
        res += ((a - b) / b) * 100
]

How can I ensure that the data exists (like how Angular is doing automatically) without this line? return 0 unless data? and data.net? and data.purchasedFor? and data.soldFor?

EDIT: Thanks to Maxim, this works perfectly:

### Watch for the net gain value and then calculate a profit % ###
$scope.$watch 'data.net', (newVal, oldVal) ->
    return 0 unless newVal?
    data = $scope.data

    a = if data.soldFor > data.purchasedFor then data.soldFor else data.purchasedFor
    b = if a is data.soldFor then data.purchasedFor else data.soldFor

    $scope.data.profit = if newVal >= 1 then '+' else '-'
    $scope.data.profit += ((a - b) / b) * 100
Was it helpful?

Solution

I would use $watch to listen on data.

See docs here

Generally $watch with flag true does deep compare.

Something like (hope you can convert it to coffee):

$scope.$watch(function () {
    return$scope.data;
   },
   function (newValue, oldValue) {
    // here you can write any action
   }, true);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top