ฟังก์ชันทางคณิตศาสตร์ในการเชื่อม AngularJS


232

มีวิธีใช้ฟังก์ชันคณิตศาสตร์ในการโยง AngularJS หรือไม่?

เช่น

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

ซอนี้แสดงให้เห็นถึงปัญหา

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


11
อีกตัวเลือกหนึ่งคือหลีกเลี่ยงการใช้คณิตศาสตร์ในแม่แบบของคุณโดยใช้ตัวกรองแทน: <p>The percentage is {{(100*count/total)| number:0}}%</p>เพิ่มเติมในความคิดเห็นด้านล่าง
Andrew Kuklewicz

2
สำหรับ Angular2 กำหนดสมาชิกองค์ประกอบprivate Math = Math;และคุณสามารถใช้งานได้
Ondra Žižka

คำตอบ:


329

คุณต้องฉีดMathเข้าไปในขอบเขตของคุณถ้าคุณจำเป็นต้องใช้มันเท่าที่ $scopeรู้เรื่องคณิตศาสตร์

วิธีที่ง่ายที่สุดคุณสามารถทำได้

$scope.Math = window.Math;

ในตัวควบคุมของคุณ วิธีการทำสิ่งที่ถูกต้องเชิงมุมคือการสร้างบริการคณิตศาสตร์ฉันเดา


1
ขอบคุณ ฉันมีกรณีการใช้งานที่ฉันมีแม่แบบหลายตัวที่มีตรรกะแตกต่างกันโดยสิ้นเชิงและต้องการแยกพวกเขาออกให้มากที่สุด สมบูรณ์แบบ
Yablargo

48
คุณควรใช้ตัวกรองอย่าวางวัตถุคณิตศาสตร์ไว้ในขอบเขต
Soviut

4
เหมาะสำหรับสิ่งที่รวดเร็วและสกปรก เยาะเย้ยอย่างรวดเร็วหรือต้องการดูว่ามีอะไรทำงานได้บ้าง ซึ่งอาจเป็นสิ่งที่คนที่ต้องการทำคณิตศาสตร์ในไฟล์เทมเพลต html ของพวกเขาต้องการ
ลาน

1
การใช้ฟังก์ชั่นในการเชื่อมจะทำให้ฟังก์ชั่นการโทรในการอัพเดทแต่ละขอบเขตและจะใช้ทรัพยากรมากเกินไป
desmati

วิธีนี้คือการที่ไม่ถูกต้อง ทำไม? 1- สร้างความสับสนต่อขอบเขตโลกเป็นความคิดที่เลวร้ายที่สุด 2- มุมมองมีความรับผิดชอบformattingดังนั้นใช้ตัวกรองแทน
Afshin Mehrabani

304

ในขณะที่คำตอบที่ยอมรับนั้นถูกต้องที่คุณสามารถฉีดMathเพื่อใช้ในเชิงมุมสำหรับปัญหาเฉพาะนี้วิธีการทั่วไป / เชิงมุมที่มากกว่าคือตัวกรองตัวเลข:

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

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับnumberตัวกรองได้ที่นี่: http://docs.angularjs.org/api/ng/filter/number


7
ไม่เพียงแค่นี้เป็นวิธีเชิงมุม แต่เป็นวิธีที่ถูกต้อง เป็นความรับผิดชอบของมุมมองในการ 'จัดรูปแบบ' ค่า
ลุค

39
แอนดรูว์ขออภัยที่ถ่วงความคิดเห็นของคุณด้วยความคิดเห็นนี้ คำตอบของคุณดีและเป็นประโยชน์ อย่างไรก็ตามฉันต้องการที่จะไม่เห็นด้วยกับความคิดเห็นอื่น ๆ ฉันมักจะประจบประแจงเมื่อผู้คนขนานนาม "เชิงมุม" ราวกับว่ามันเป็นส่วนหนึ่งของการพัฒนาที่สมบูรณ์แบบ มันไม่ใช่ OP ถามโดยทั่วไปถึงวิธีรวมฟังก์ชั่นทางคณิตศาสตร์ในการเชื่อมโยงโดยมีการปัดเศษแสดงเป็นตัวอย่างเท่านั้น ในขณะที่คำตอบนี้อาจเป็น "วิธีเชิงมุม" โดยนักสอนเพื่อแก้ไขปัญหาคณิตศาสตร์อย่างแน่นอน แต่ก็ไม่ได้ตอบคำถามอย่างเต็มที่
kbrimington

1
ขออภัยสำหรับโบราณคดี แต่สิ่งนี้ไม่ถูกต้องเมื่อคุณต้องการตัวเลขเป็นเอาต์พุต {{1234.567|number:2}}แสดงผลเป็นหรือ1,234.57 1 234,57หากคุณพยายามที่จะส่งผ่านไปยัง<input type="number" ng-value="1234.567|number:2">คุณจะว่างเปล่าใส่เพราะค่าไม่ใช่จำนวนที่ถูกต้อง แต่เป็นตัวแทนสตริงขึ้นอยู่กับสถานที่
SWilk

61

ฉันคิดว่าวิธีที่ดีที่สุดคือการสร้างตัวกรองเช่นนี้:

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

ดังนั้นมาร์กอัปจะเป็นดังนี้:

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

ซอที่อัปเดต: http://jsfiddle.net/BB4T4/


ตัวกรองตัวเลขตามที่ระบุไว้ในคำตอบของ klaxon จะทำแบบเพดานอยู่แล้วดังนั้นจึงไม่จำเป็นต้องทำเช่นนั้น
Kim

ฉันทำสิ่งที่คล้ายกันเพียงใช้ตัวกรองเพื่อสร้างตัวจับเวลาตามที่ฉันต้องการ กล่าวอีกนัยหนึ่งฉันจะใช้เวลาปัจจุบันและจัดรูปแบบเป็นสตริงตามที่ฉันเห็นว่าเหมาะสมโดยใช้ตัวกรองที่กำหนดเอง ตัวกรองตัวเลขก็ดีเช่นกันเมื่อคุณต้องการปัดเศษตัวเลขของคุณ แต่สำหรับฟังก์ชันพื้นและฝ้าเพดานมันไร้ประโยชน์
Gabriel Lovetro

37

นี่เป็นคำตอบที่มีขนดกเพราะคุณไม่ได้ให้บริบทที่เต็มไปด้วยสิ่งที่คุณทำ คำตอบที่ยอมรับจะใช้งานได้ แต่ในบางกรณีอาจทำให้ประสิทธิภาพต่ำ นั่นและมันจะยากกว่าที่จะทดสอบ

หากคุณทำสิ่งนี้เป็นส่วนหนึ่งของรูปแบบคงที่ดี คำตอบที่ได้รับการยอมรับจะใช้ได้แม้ว่ามันจะไม่ใช่เรื่องง่ายที่จะทดสอบ

หากคุณต้องการที่จะเป็น "เชิงมุม" เกี่ยวกับเรื่องนี้:

คุณจะต้องการให้ "ตรรกะทางธุรกิจ" (เช่นตรรกะที่เปลี่ยนแปลงข้อมูลที่จะแสดง) จากมุมมองของคุณ นี่คือเพื่อให้คุณสามารถหน่วยทดสอบตรรกะของคุณและเพื่อให้คุณไม่จบการมีเพศสัมพันธ์ควบคุมและมุมมองของคุณ ในทางทฤษฎีคุณควรจะสามารถชี้คอนโทรลเลอร์ของคุณไปยังมุมมองอื่นและใช้ค่าเดียวกันจากขอบเขต (ถ้ามันสมเหตุสมผล)

คุณจะต้องพิจารณาด้วยว่าการเรียกฟังก์ชั่นใด ๆ ที่อยู่ภายในการเชื่อมโยง (เช่น{{}}หรือng-bindหรือng-bind-html) จะต้องถูกประเมินในทุกส่วนย่อยเพราะเชิงมุมไม่มีทางรู้ได้ว่าค่ามีการเปลี่ยนแปลงหรือไม่เหมือนที่มันมีคุณสมบัติ ในขอบเขต

วิธี "เชิงมุม" ในการทำเช่นนี้คือการแคชค่าในคุณสมบัติบนขอบเขตการเปลี่ยนแปลงโดยใช้เหตุการณ์ ng-change หรือแม้แต่ $ watch

ตัวอย่างเช่นแบบคงที่:

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>

และตอนนี้คุณสามารถทดสอบได้!

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.
  });
});

คุณสามารถรวบรวมองค์ประกอบแล้วทดสอบค่าที่พบในองค์ประกอบ dom ที่ต้องการจริงเนื่องจากคุณอาจใช้ตัวกรองการแปลเช่นกัน
FlavourScape

คำตอบที่ดี. แต่สงสัยว่าทำไม prepend ด้วย$windowเพราะดูเหมือนว่าจะทำงานกับแผนเพียงMath.round()?
Neel

3
@Neel - $ window ให้คุณจำลองการMathทดสอบได้ง่ายขึ้น ในทางกลับกันคุณสามารถสร้างบริการคณิตศาสตร์และฉีดได้
เบ็นเลช

8

ทำไมไม่รวม obj ทางคณิตศาสตร์ทั้งหมดลงในตัวกรอง

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


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

        return 0;
    }
}

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

และที่จะใช้:

{{number_var | คณิตศาสตร์: 'ceil'}}


8

ตัวเลือกที่ดีกว่าคือการใช้:

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

มันตั้งค่าเริ่มต้นของสมการที่ 0 ในกรณีที่เมื่อค่าไม่ได้เริ่มต้น


6

หากคุณต้องการทำรอบง่ายๆใน Angular คุณสามารถตั้งค่าตัวกรองภายในนิพจน์ของคุณได้อย่างง่ายดาย ตัวอย่างเช่น:

{{ val | number:0 }}

ดูตัวอย่างCodePenนี้& สำหรับตัวเลือกตัวกรองตัวเลขอื่น ๆ

เอกสารเชิงมุมเกี่ยวกับการใช้ตัวกรองตัวเลข


6

วิธีที่ง่ายที่สุดในการทำคณิตศาสตร์อย่างง่ายด้วย Angular นั้นอยู่ใน markup HTML โดยตรงสำหรับการผูกแต่ละครั้งตามที่ต้องการโดยสมมติว่าคุณไม่จำเป็นต้องทำการคำนวณจำนวนมากบนหน้าเว็บของคุณ นี่คือตัวอย่าง:

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

ในกรณีนี้คุณเพียงแค่ทำคณิตศาสตร์ใน () แล้วใช้ตัวกรอง | เพื่อรับคำตอบตัวเลข นี่คือข้อมูลเพิ่มเติมเกี่ยวกับการจัดรูปแบบตัวเลขเชิงมุมเป็นข้อความ:

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


4

ผูกวัตถุคณิตศาสตร์ระดับโลกเข้ากับขอบเขต (อย่าลืมใช้ $ window ไม่ใช่หน้าต่าง)

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

ใช้การรวมใน HTML ของคุณ:

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

หรือสร้างตัวกรองสำหรับฟังก์ชันคณิตศาสตร์เฉพาะที่คุณอยู่หลังจาก:

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

ใช้ตัวกรองใน HTML ของคุณ:

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

2

นั่นดูไม่เหมือนวิธีเชิงมุมในการทำมัน ฉันไม่แน่ใจทั้งหมดว่าทำไมมันใช้งานไม่ได้ แต่คุณอาจต้องเข้าถึงขอบเขตเพื่อใช้ฟังก์ชันเช่นนั้น

คำแนะนำของฉันคือการสร้างตัวกรอง นั่นคือวิธีการเชิงมุม

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

จากนั้นใน HTML ให้ทำดังนี้

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

1

numberกรองรูปแบบจำนวนที่มีหลายพันตัวคั่นดังนั้นจึงไม่เคร่งครัดฟังก์ชั่นทางคณิตศาสตร์

นอกจากนี้ยังมีทศนิยมของ 'จำกัด' ไม่ceilสับใด ๆ ทศนิยม (เป็นคำตอบอื่น ๆ บางคนจะนำคุณไปสู่เชื่อว่า) แต่roundไอเอ็นจีพวกเขา

ดังนั้นสำหรับฟังก์ชั่นคณิตศาสตร์ใด ๆ ที่คุณต้องการคุณสามารถฉีด (เยาะเย้ยได้ง่ายกว่าการฉีดวัตถุคณิตศาสตร์ทั้งหมด) ดังนี้:

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

ไม่จำเป็นต้องห่อในฟังก์ชั่นอื่นเช่นกัน


0

นี่เป็นบทสรุปสั้น ๆ ของคำตอบสามข้อ (โดย Sara InésCalderón, klaxon และ Gothburz) แต่เมื่อพวกเขาเพิ่มสิ่งที่สำคัญฉันคิดว่ามันคุ้มค่าที่จะเข้าร่วมโซลูชั่นและเพิ่มคำอธิบายเพิ่มเติม

เมื่อพิจารณาตัวอย่างของคุณคุณสามารถทำการคำนวณในแม่แบบของคุณโดยใช้:

{{ 100 * (count/total) }}

อย่างไรก็ตามการทำเช่นนี้อาจส่งผลให้เกิดทศนิยมจำนวนมากดังนั้นการใช้ตัวกรองจึงเป็นวิธีที่ดี

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

ตามค่าเริ่มต้นตัวกรองตัวเลขจะมีตัวเลขเศษส่วนได้ถึงสามหลักซึ่งเป็นที่ที่อาร์กิวเมนต์ fractionSizeมีประโยชน์มาก ( {{ 100 * (count/total) | number:fractionSize }}) ซึ่งในกรณีของคุณจะเป็น:

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

ซึ่งจะเป็นการปัดเศษผลลัพธ์แล้ว:

สิ่งสุดท้ายที่ต้องพูดถึงถ้าคุณพึ่งพาแหล่งข้อมูลภายนอกเป็นวิธีที่ดีที่จะให้ค่าทางเลือกที่เหมาะสม(ไม่เช่นนั้นคุณอาจเห็น NaN หรือไม่มีอะไรในไซต์ของคุณ):

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

Sidenote: ขึ้นอยู่กับข้อกำหนดของคุณคุณอาจจะแม่นยำยิ่งขึ้นเมื่อใช้ทางเลือก / กำหนดทางเลือกในระดับที่ต่ำกว่าอยู่แล้ว (เช่น{{(100 * (count || 10)/ (total || 100) | number:2)}}) แม้ว่าสิ่งนี้อาจไม่สมเหตุสมผลเสมอไป ..


0

ตัวอย่าง Angular Typescript โดยใช้ไพพ์

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

@NgModule({
  declarations: [
    MathPipe,

จากนั้นใช้ในเทมเพลตของคุณดังนี้:

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

TypeError: Math [args] ไม่ใช่ฟังก์ชัน
MattEnth
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.