แสดงค่าโดยไม่มีการผูกข้อมูล


87

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

ทั้งสองตัวอย่างต่อไปนี้ใช้การผูกข้อมูล:

<div>{{value}}</div>

<div data-ng-bind="value"></div>

ฉันจะแสดงผลvalue โดยไม่มีการผูกข้อมูลได้อย่างไร


อินพุตและเอาต์พุตของคุณคืออะไร โปรดอธิบาย
Nitish Kumar

3
ตัวอย่างของคุณเป็นการเชื่อมข้อมูลทางเดียว (การเปลี่ยนแปลงโมเดล -> ดูการอัปเดต) ng-modelช่วยให้คุณเชื่อมโยงข้อมูลสองทาง: การเปลี่ยนแปลงโมเดล -> ดูการอัปเดตดูการเปลี่ยนแปลง -> การอัปเดตโมเดล
Mark Rajcok

1
ปรับปรุง ขอโทษฉันหมายความว่าฉันไม่ต้องการผูกข้อมูลเลย
Blowsie

10
ฉันไม่คิดว่าคำถามนี้แย่มากหรือสมควรได้รับการโหวตลดลง เป็นเรื่องปกติมากที่ต้องการปิดใช้งานการผูกข้อมูลเพื่อป้องกันนาฬิกาที่ไม่จำเป็น
OverZealous

4
UPDATE: ใครก็ตามที่อ่านบทความนี้จะพบว่าวิดีโอนี้มีประโยชน์อย่างยิ่ง youtube.com/watch?v=zyYpHIOrk_Y
Blowsie

คำตอบ:


141

เชิงมุม 1.3+

ใน 1.3 Angular สนับสนุนสิ่งนี้โดยใช้ไวยากรณ์ต่อไปนี้

<div>{{::message}}</div>

ดังที่กล่าวไว้ในคำตอบนี้ .


เชิงมุม 1.2 และต่ำกว่า

นี่เป็นเรื่องง่ายและไม่จำเป็นต้องมีปลั๊กอิน ลองดู.

คำสั่งเล็ก ๆ นี้จะทำให้สิ่งที่คุณพยายามบรรลุได้อย่างง่ายดาย

app.directive('bindOnce', function() {
    return {
        scope: true,
        link: function( $scope ) {
            setTimeout(function() {
                $scope.$destroy();
            }, 0);
        }
    }
});

คุณสามารถผูกครั้งเดียวเช่นนี้

<div bind-once>I bind once - {{message}}</div>

คุณสามารถผูกได้ตามปกติ

<div ng-bind="message" bind-once></div>

การสาธิต: http://jsfiddle.net/fffnb/

บางท่านอาจใช้ angular batarang และตามที่กล่าวไว้ในความคิดเห็นหากคุณใช้คำสั่งนี้องค์ประกอบยังคงแสดงว่ามีผลผูกพันเมื่อไม่ใช่ฉันค่อนข้างแน่ใจว่าสิ่งนี้เกี่ยวข้องกับคลาสที่แนบมากับองค์ประกอบดังนั้น ลองนี้มันควรจะทำงาน(ไม่ได้ทดสอบ) แจ้งให้เราทราบในความคิดเห็นหากได้ผลสำหรับคุณ

app.directive('bindOnce', function() {
    return {
        scope: true,
        link: function( $scope, $element ) {
            setTimeout(function() {
                $scope.$destroy();
                $element.removeClass('ng-binding ng-scope');
            }, 0);
        }
    }
});

@ x0b : หากคุณมี OCD และต้องการลบclassแอตทริบิวต์ว่างให้ทำเช่นนี้

!$element.attr('class') && $element.removeAttr('class')

ฉันยังไม่ได้ทดสอบปลั๊กอิน แต่ฉันคิดว่าเครื่องมือ AngularJS chrome จะไม่แสดงองค์ประกอบการผูกครั้งเดียวเป็นการผูกตามที่ตัวอย่างของคุณทำ แนวทางที่น่าสนใจฉันจะทดสอบทั้งสองวิธีในไม่ช้า
Blowsie

ดูสิ่งนี้ - มันแสดงทั้งการผูกdl.dropboxusercontent.com/u/14037764/Development/stackoverflow/…
Blowsie

1
ไม่ต้องสงสัยเลยว่าเป็นเพราะถ้าคลาส ng-binding ที่คุณสามารถลบออกได้อย่างง่ายดาย
iConnor

4
สิ่งนี้ยอดเยี่ยมและง่ายกว่าปลั๊กอิน bindonce มาก ฉันเพิ่มความสามารถในการรอเงื่อนไขก่อนที่จะทำลายขอบเขตและมันก็มีประโยชน์มาก ขอบคุณ.
Yaron

1
@ คอนเนอร์ไม่เห็นด้วย ตัวอย่างเช่นฉันได้รับออบเจ็กต์วิดีโอ ($ scope.video) จาก REST API และฉันต้องการเชื่อมโยงชื่อวิดีโอแบบครั้งเดียว ($ scope.video.title) แม้ว่าฉันจะแก้ไขคำสัญญาก่อนที่จะเพิ่มขอบเขตในตัวควบคุม แต่ฉันก็ยังต้องประกาศว่า ng-bind = "video.title" bind-once บน DOM ตอนนี้ก่อนที่คำสัญญาจะได้รับการแก้ไข video.title ไม่ได้กำหนดไว้และขอบเขตจะถูกทำลายก่อนที่จะกำหนด video.title วิธีแก้ปัญหาที่ฉันมีคือการรวมองค์ประกอบในแฟล็ก loading / init บางประเภท, ng-if = "someLoadingFlag" แต่เป็นรูปแบบที่ไม่ดี
SirTophamHatt

49

ดูเหมือนว่า Angular 1.3 (เริ่มต้นด้วยเบต้า 10) มีการผูกครั้งเดียวในตัว:

https://docs.angularjs.org/guide/expression#one-time-binding

การผูกครั้งเดียว

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


1
คำตอบนี้ครั้งแล้วครั้งเล่า ฉันไม่สามารถยกย่องคุณคาร์ลได้มากพอ! ฉันขอแนะนำให้ใช้ฟีเจอร์นี้ในทุกที่ที่สมเหตุสมผล
XDS

1
ว้าวฉันดีใจจริงๆที่เลื่อนลงมา ฉันจะขอให้คอนเนอร์อ้างอิงสิ่งนี้ในคำตอบที่เขายอมรับ
JSager

ฉันมีตาราง / รายการที่มี 2,000 บรรทัดและใช้ตัวดำเนินการผูกครั้งเดียวแอปของฉันทำงานช้ามากเมื่อแสดง / แสดงรายการครั้งแรก ช้ามากเบราว์เซอร์ถามฉันสองหรือสามครั้งว่าฉันต้องการหยุดเรียกใช้สคริปต์ไหม!
Billy G

@ billy-g คุณสามารถโพสต์ jsfiddle หรือ plunker เพื่ออธิบายปัญหาได้หรือไม่
James Daily

@ James Daily: นี่คือกรณี "ปกติ" plnkr.co/edit/rCRP0T5fSgNIllx7F27yและนี่คือกรณี "นิพจน์ครั้งเดียว" plnkr.co/edit/Rd5VBVjkcX3sTJYGypUrแต่ ... ฉันไม่สามารถทำซ้ำได้ที่นั่น อย่างไรก็ตามมันไม่เร็วกว่าด้วย "นิพจน์ครั้งเดียว" และฉันต้องทำการตรวจสอบเพิ่มเติมเพื่อหาสาเหตุที่เกิดขึ้นในสภาพแวดล้อมของฉัน (ฉันใช้ 1.3 beta 18 ของ angularjs)
Billy G

20

ใช้โมดูล bindonce คุณจะต้องรวมไฟล์ JS และเพิ่มเป็นการอ้างอิงกับโมดูลแอปของคุณ:

var myApp = angular.module("myApp", ['pasvaz.bindonce']);

ไลบรารีนี้อนุญาตให้คุณแสดงรายการที่ถูกผูกไว้เพียงครั้งเดียว - เมื่อเริ่มต้นครั้งแรก การอัปเดตเพิ่มเติมใด ๆ ของค่าเหล่านั้นจะถูกละเว้น เป็นวิธีที่ยอดเยี่ยมในการลดจำนวนนาฬิกาบนหน้าสำหรับสิ่งที่จะไม่เปลี่ยนแปลงหลังจากแสดงผล

ตัวอย่างการใช้งาน:

<div bo-text="value"></div>

เมื่อใช้เช่นนี้คุณสมบัติภายใต้valueจะถูกตั้งค่าเมื่อพร้อมใช้งาน แต่นาฬิกาจะถูกปิดใช้งาน


1
ฉันกำลังจะเขียนคำตอบ "เขียนคำสั่งของคุณเอง ... " แต่ดูเหมือนว่าจะมีคนทำแบบนั้นให้เราเรียบร้อยแล้ว
Mark Rajcok

3
Bindonce มีประโยชน์มากพอที่จะรวมเป็นไลบรารีเสริมในตัวเช่น$resource.
OverZealous

6
นี่คือสิ่งที่ฉันกำลังมองหา แต่ฉันคาดหวังว่าสิ่งนี้จะถูกสร้างขึ้นในเชิงมุม!
Blowsie

7

การเปรียบเทียบระหว่างคำตอบของ @OverZealous และ @Connor:

ด้วย ngRepeat ดั้งเดิมของเชิงมุม: 15 วินาทีสำหรับ 2,000 แถวและ 420mo ของ RAM ( Plunker )

ด้วย ngRepeat และโมดูลของ @OverZealous: 7s สำหรับ 2,000 แถวและ 240mo ของ RAM ( Plunker )

ด้วย ngRepeat และคำสั่งของ @Connor: 8s สำหรับ 2,000 แถวและ 500mo ของ RAM ( Plunker )

ฉันทำการทดสอบกับ Google Chrome 32


1
จะเป็นการดีที่ได้angular-onceเปรียบเทียบ ขอบคุณ.
alecxe

@alecxe: ฉันวางแผนที่จะทำการทดสอบเมื่อมีการเผยแพร่โครงสร้าง AngularJS 1.3 ที่เสถียร
Gabriel

ขอบคุณอย่าลืมใส่angular-onceแพ็คเกจ (ฉันโพสต์ไว้เป็นตัวเลือกอื่นที่นี่)
alecxe

5

นอกจากนี้ยังมีangular-onceแพ็คเกจ:

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

angular-onceได้รับแรงบันดาลใจจากbindonceและให้once-*คุณลักษณะที่คล้ายกัน:

<ul>
    <li ng-repeat="user in users">
      <a once-href="user.profileUrl" once-text="user.name"></a>
        <a once-href="user.profileUrl"><img once-src="user.avatarUrl"></a>
        <div once-class="{'formatted': user.description}" once-bind="user.description"></div>
    </li>
</ul>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.