AngularJS bağlarında matematik fonksiyonları


232

AngularJS bağlarında matematik fonksiyonlarını kullanmanın bir yolu var mı?

Örneğin

<p>The percentage is {{Math.round(100*count/total)}}%</p>

Bu keman sorunu gösteriyor

http://jsfiddle.net/ricick/jtA99/1/


11
Başka bir seçenek, bunun yerine bir filtre kullanarak şablonlarınızda Math kullanmaktan kaçınmaktır: <p>The percentage is {{(100*count/total)| number:0}}%</p>daha fazla yorum aşağıda.
Andrew Kuklewicz

2
Angular2 için bir bileşen üyesi tanımlayın private Math = Math;ve onu kullanın.
Ondra Febižka

Yanıtlar:


329

Eğer Matematik hakkında hiçbir şey bilmiyor Mathgibi kullanmak gerekiyorsa, kapsam içine enjekte etmek zorunda $scope.

En basit yol, yapabilirsin

$scope.Math = window.Math;

kontrolörünüzde. Bunu doğru bir şekilde yapmanın açısal yolu bir Matematik hizmeti oluşturmak olurdu sanırım.


1
Teşekkürler. Tamamen farklı mantık ile birden fazla şablon var ve bunları mümkün olduğunca izole etmek istiyorum bir kullanım durum var. Mükemmel
Yablargo

48
Math nesnesini kapsama koymamak için bir filtre kullanmalısınız.
Soviut

4
Bu hızlı ve kirli şeyler için iyidir; hızlı bir şekilde alay ediyor ya da bir şeyin nasıl çalıştığını görmek istiyor. Muhtemelen html şablon dosyalarında matematik yapmak isteyen biri ne ister.
Lan

1
Bağlamalardaki işlevleri kullanmak, her kapsamın güncellemesinde çağrılacak işlevi yapar ve çok fazla kaynak kullanır.
desmati

Bu çözüm yanlış . neden? 1- Küresel kapsamı kirletmek şimdiye kadarki en kötü fikir. 2-görünümler sorumludur formatting, bu nedenle filtre kullanın.
Afshin Mehrabani

304

Kabul edilen cevap, Mathaçısal olarak kullanmak için enjekte edebileceğiniz doğru olsa da , bu özel sorun için, daha geleneksel / açısal yol sayı filtresidir:

<p>The percentage is {{(100*count/total)| number:0}}%</p>

numberFiltre hakkında daha fazla bilgiyi buradan edinebilirsiniz: http://docs.angularjs.org/api/ng/filter/number


7
Bu sadece Açısal yol değil, doğru yol. Değeri 'biçimlendirmek' görünümün sorumluluğudur.
Luke

39
Andrew, yazınızı bu yorumla karıştırdığınız için üzgünüm. Cevabınız iyi ve yararlı; ancak, diğer yorumlara katılmıyorum. İnsanlar "açısal yol" a çıktıklarında sanki mükemmel gelişimin bir paragonu gibi. Öyle değil. OP genel olarak matematik fonksiyonlarının bir bağlamaya nasıl dahil edileceğini sordu ve yuvarlama sadece örnek olarak sunuldu. Bu cevap, tam bir matematik problemini çözmek için puristler tarafından "açısal yol" olsa da, soruyu tam olarak cevaplamaz.
kbrimington

1
Arkeoloji için özür dileriz, ancak çıktı olarak bir Sayıya ihtiyacınız olduğunda bu yanlıştır. veya {{1234.567|number:2}}olarak işler . Bunu iletmeye çalışırsanız , değer DOĞRU BİR NUMARAL DEĞİLDİR, ancak yerel ayara bağlı dize temsili olduğundan girdiyi boşaltırsınız. 1,234.571 234,57<input type="number" ng-value="1234.567|number:2">
17'de

61

Bunu yapmanın en iyi yolunun böyle bir filtre oluşturarak olduğunu düşünüyorum:

myModule.filter('ceil', function() {
    return function(input) {
        return Math.ceil(input);
    };
});

işaretleme şöyle görünür:

<p>The percentage is {{ (100*count/total) | ceil }}%</p>

Güncellenmiş keman: http://jsfiddle.net/BB4T4/


Klakson'un cevabında verilen sayı filtresi tavanı zaten yapacak, bu yüzden buna gerek yok.
Kim

Benzer bir şey yaptım, sadece zamanlayıcıyı istediğim gibi oluşturmak için filtreyi kullanarak. Başka bir deyişle, özel bir filtre kullanarak uygun gördüğümde şimdiki zamanı alıp bir dizeye biçimlendirirdim. Rakamlarınızı yuvarlamak istediğinizde de sayı filtresi iyidir, ancak zemin ve tavan işlevleri için işe yaramaz.
Gabriel Lovetro

37

Bu cevap verilecek tüylü bir soru, çünkü ne yaptığınızın tam bağlamını vermediniz. Kabul edilen cevap işe yarayacaktır, ancak bazı durumlarda düşük performansa neden olacaktır. Bunu test etmek daha zor olacak.

Bunu statik bir formun parçası olarak yapıyorsanız, iyi. Kabul edilen cevap, test edilmesi kolay olmasa bile işe yarayacaktır ve hinky.

Bu konuda "Açısal" olmak istiyorsanız:

Herhangi bir "iş mantığını" (yani görüntülenecek verileri değiştiren mantığı) görünümlerinizin dışında tutmak istersiniz. Bu, mantığınızı birim olarak test edebilmeniz için kontrol cihazınızı ve görüşünüzü sıkıca birleştirmezsiniz. Teorik olarak, kontrol cihazınızı başka bir görünüme yönlendirebilmeniz ve kapsamlardaki aynı değerleri kullanabilmeniz gerekir. (Mantıklı geliyorsa).

Ayrıca, bir bağlamanın içindeki ( {{}}veya ng-bindveya ng-bind-html) herhangi bir işlev çağrısının her özette değerlendirilmesi gerekeceğini düşünmek isteyeceksiniz , çünkü açısal değerin bir özellikte değişip değişmediğini bilmiyor kapsamda.

Bunu yapmanın "açısal" yolu, bir ng-change olayı veya hatta $ watch kullanarak değişiklik kapsamındaki bir özellikteki değeri önbelleğe almak olacaktır.

Örneğin statik bir formla:

angular.controller('MainCtrl', function($scope, $window) {
   $scope.count = 0;
   $scope.total = 1;

   $scope.updatePercentage = function () {
      $scope.percentage = $window.Math.round((100 * $scope.count) / $scope.total);
   };
});
<form name="calcForm">
   <label>Count <input name="count" ng-model="count" 
                  ng-change="updatePercentage()"
                  type="number" min="0" required/></label><br/>
   <label>Total <input name="total" ng-model="total"
                  ng-change="updatePercentage()"
                  type="number" min="1" required/></label><br/>
   <hr/>
   Percentage: {{percentage}}
</form>

Ve şimdi test edebilirsiniz!

describe('Testing percentage controller', function() {
  var $scope = null;
  var ctrl = null;

  //you need to indicate your module in a test
  beforeEach(module('plunker'));

  beforeEach(inject(function($rootScope, $controller) {
    $scope = $rootScope.$new();

    ctrl = $controller('MainCtrl', {
      $scope: $scope
    });
  }));

  it('should calculate percentages properly', function() {
    $scope.count = 1;
    $scope.total = 1;
    $scope.updatePercentage();
    expect($scope.percentage).toEqual(100);

    $scope.count = 1;
    $scope.total = 2;
    $scope.updatePercentage();
    expect($scope.percentage).toEqual(50);

    $scope.count = 497;
    $scope.total = 10000;
    $scope.updatePercentage();
    expect($scope.percentage).toEqual(5); //4.97% rounded up.

    $scope.count = 231;
    $scope.total = 10000;
    $scope.updatePercentage();
    expect($scope.percentage).toEqual(2); //2.31% rounded down.
  });
});

öğeyi derleyebilir ve dom öğesinde bulunan değeri test edebilirsiniz. yerelleştirme filtreleri de kullanıyor olabileceğiniz için bu tercih edilir.
FlavorScape

İyi cevap. Ama neden $windowsadece planla çalışıyor gibi göründüğünü merak ediyorsun Math.round()?
Neel

3
@Neel - $ penceresi, Mathtestler için alay etmenizi sağlar . Alternatif olarak, bir Matematik hizmeti oluşturabilir ve enjekte edebilirsiniz.
Ben Lesh

8

Neden tüm matematik nesnesini bir filtreye sarmıyorsunuz?

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


function math() {
    return function(input,arg) {
        if(input) {
            return Math[arg](input);
        }

        return 0;
    }
}

return app.filter('math',[math]);

ve kullanmak için:

{{number_var | Matematik: 'ceil'}}


8

Daha iyi bir seçenek kullanmaktır:

{{(100*score/questionCounter) || 0 | number:0}}

Değerlerin başlatılmadığı durumda varsayılan denklem değerini 0 olarak ayarlar.



6

Angular ile basit matematik yapmanın en kolay yolu, sayfanızda toplu hesaplamalar yapmanız gerekmediği varsayılarak, gerektiğinde tek tek ciltlemeler için doğrudan HTML biçimlendirmesidir. İşte bir örnek:

{{(data.input/data.input2)| number}} 

Bu durumda, sadece () matematik yapmak ve sonra bir filtre | bir sayı cevabı almak için. Açısal sayıları metin olarak biçimlendirme hakkında daha fazla bilgi:

https://docs.angularjs.org/api/ng/filter


4

Genel Math nesnesini kapsama bağlayın (pencereyi değil $ penceresini kullanmayı unutmayın)

$scope.abs = $window.Math.abs;

HTML'nizdeki bağlayıcıyı kullanın:

<p>Distance from zero: {{abs(distance)}}</p>

Veya peşinde olduğunuz belirli Matematik işlevi için bir filtre oluşturun:

module.filter('abs', ['$window', function($window) {
  return function(n) {
    return $window.Math.abs($window.parseInt(n));
  };
});

HTML'nizdeki filtreyi kullanın:

<p>Distance from zero: {{distance | abs}}</p>

2

Bu çok Açısal bir yol gibi görünmüyor. Neden işe yaramadığından tam olarak emin değilim, ancak böyle bir işlevi kullanmak için muhtemelen kapsama erişmeniz gerekir.

Benim önerim bir filtre oluşturmak olacaktır. Açısal yol budur.

myModule.filter('ceil', function() {
    return function(input) {
        return Math.ceil(input);
    };
});

Ardından HTML'nizde bunu yapın:

<p>The percentage is {{ (100*count/total) | ceil }}%</p>

1

numberO kesinlikle bir matematik fonksiyonu değil böylece filtre, binlerce ayırıcılar ile numarayı biçimlendirir.

Dahası, ondalık 'sınırlayıcısı', ceilkesilmiş ondalık sayılar değil (diğer bazı cevaplar sizi inanmanıza neden olacağı için) değil round, onlara verir.

Yani istediğiniz herhangi bir matematik fonksiyonu için, onu enjekte edebilirsiniz (bütün Math nesnesini enjekte etmekten daha kolay):

myModule.filter('ceil', function () {
  return Math.ceil;
});

Başka bir işleve sarmanıza gerek yok.


0

Bu, üç yanıtın (Sara Inés Calderón, klaxon ve Gothburz tarafından) aşağı yukarı bir özeti, ancak hepsi önemli bir şey ekledikçe, çözümlere katılmaya ve biraz daha açıklama eklemeye değer olduğunu düşünüyorum.

Örneğinizi göz önünde bulundurarak, aşağıdakileri kullanarak şablonunuzda hesaplamalar yapabilirsiniz:

{{ 100 * (count/total) }}

Bununla birlikte, bu çok sayıda ondalık basamağa neden olabilir, bu nedenle filtreleri kullanmak iyi bir yoldur:

{{ 100 * (count/total) | number }}

Varsayılan olarak, sayı filtresi en fazla üç kesirli basamak bırakacaktır , bu durumda fractionSize argümanının oldukça kullanışlı ( {{ 100 * (count/total) | number:fractionSize }}) olduğu durumda, bu durumda:

{{ 100 * (count/total) | number:0 }}

Bu ayrıca sonucu yuvarlayacak:

Bahsetmeniz gereken son şey, bir dış veri kaynağına güveniyorsanız, uygun bir geri dönüş değeri sağlamak muhtemelen iyi bir uygulamadır (aksi takdirde sitenizde NaN veya hiçbir şey görebilirsiniz):

{{ (100 * (count/total) | number:0) || 0 }}

Sidenote: Spesifikasyonlarınıza bağlı olarak, yedeklerinizle daha hassas olabilir / daha düşük düzeylerde yedekleri tanımlayabilirsiniz (örn. {{(100 * (count || 10)/ (total || 100) | number:2)}}). Yine de, bu her zaman anlamlı olmayabilir.


0

Boru kullanarak açısal dizgi örneği.

math.pipe.ts

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'math',
})

export class MathPipe implements PipeTransform {

  transform(value: number, args: any = null):any {
      if(value) {
        return Math[args](value);
      }
      return 0;
  }
}

@NgModule bildirimlerine ekle

@NgModule({
  declarations: [
    MathPipe,

ardından şablonunuzda şu şekilde kullanın:

{{(100*count/total) | math:'round'}}

TypeError: Matematik [args] bir işlev değil
MattEnth
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.