Web Design

AngularJS, Bài 2: Ràng buộc dữ liệu hai chiều và ngModel

Một trong số những ưu điểm rất hay của AngularJS và sau này được Angular kế thừa là ràng buộc dữ liệu hai chiều (two-way data binding). Tất nhiên, bạn có thể làm được điều tương tự với JS cơ bản. Nhưng thay vì hàng hà sa số dòng code và có thể dẫn tới sai sót do bạn quên một var nào đó, với AngularJS, mọi chuyện sẽ đơn giản và an toàn hơn vô cùng.

AngularJS

Trước khi vào bài học, mời các bạn nhìn lại phần code “thần thánh” trong bài trước:

1. Two-way data binding là gì?

Bây giờ, hãy quay ngược thời gian lại thời điểm bạn đang học lớp 4, và thầy cô giáo của bạn đang đọc chính tả cho bạn viết. Thầy cô đọc tới đâu, bạn viết vào tập tới đó, với nội dung giống như thầy cô giáo bạn đọc. Quay lại thời điểm này, bạn có thể nói thầy cô và bạn lúc đó có mối quan hệ ràng buộc dữ liệu – tức data binding. Khi bạn ràng buộc một biến dữ liệu vào một biến dữ liệu gốc khác, thì khi giá trị của biến dữ liệu gốc thay đổi, giá trị của biến dữ liệu được ràng buộc cũng phải thay đổi theo đúng như vậy. Còn đối với suy nghĩ theo hướng lập trình máy móc, thì data binding chỉ đơn giản là realtime data change listener mà thôi.

2. Ví dụ đơn giản về data binding với Javascript cơ bản:

Trước hết, tôi đưa ra ví dụ rất đơn giản với Javascript cơ bản về data binding. Ý tưởng của tôi là tạo một thẻ <p> có textContent được cập nhật liên tục theo value của một text <input>. Tôi sẽ code luôn trên trang HTML “thần thánh” của chúng ta.

Bạn thấy đó, khi bạn nhập bất kì thứ gì vào ô text <input>, textContent của <p> sẽ được cập nhật và “giống y chang” những gì mà bạn đã và đang nhập vào ô text <input>. Ta nói data của <p> được bind (trói buộc, ràng buộc) vào data của text <input>. Tuy nhiên, trên thực tế, thì nó không “realtime”, vì callback điều chỉnh textContent được thực hiện mỗi lần keyup. Thứ hai là việc cập nhật dữ liệu còn thụ động. Và cuối cùng, nếu bạn có tới 100 cái <p> cùng lắng nghe mỗi cái text <input> kia, trong khi mỗi cái <p> nằm trong tầng lớp khác nhau, và có cái phải listen, có cái lại không, thì bạn phải code bằng tay vô cùng dài dòng, tốn thời gian mà nhiều khi bạn lại bỏ sót mấy thứ.

3. Two-way data binding với ng-model trong AngularJS:

Vấn đề phía trên sẽ được giải quyết rất nhanh gọn với ng-model trong AngularJS. Về bản chất, thì ng-model là một Angular directive. Tôi sẽ nói về directives ở các bài sau. Còn ở đây, bạn cứ coi ng-model là một attribute/property linh động, có thể gán cho bất kì một HTML element nào có chứa nội dung (value hay textContent, v.v…). Nó sẽ nhận một giá trị là một biến giống như con trỏ trong C++ vậy. Sẽ dễ hiểu hơn nếu bạn quan sát ví dụ bên dưới trước khi tôi giải thích cụ thể:

Bạn sẽ để ý hai điều. Thứ nhất, tôi gán ng-model vào text <input> và coi như ng-model là một attribute của <input> vậy, mặc dù trên thực tế, <input> làm gì có attr nào là ng-model! Bạn chỉ dùng được ng-model khi làm việc với AngularJS mà thôi, tức là có gọi <script> trỏ tới angular.js. Tên ng-model này nhận giá trị gì trong cặp dấu nháy, thì bạn có thể coi đó là tên của biến (con trỏ). Và khi lấy giá trị của nó ra, thì bạn sẽ cần gọi đúng nó, chẳng hạn như cái nằm giữa cặp tag <p>. Thứ hai, để lấy giá trị thực của một ng-model ra, bạn sẽ bỏ tên biến trong cặp ngoặc nhọn đôi như bên trên. Ở đây, {{data}} – được gọi là String expression – có nghĩa là lấy giá trị thực của tên ng-model=’data’ ra mà dùng. Và một lần nữa, bạn chỉ có thể dùng String expression với AngularJS và Angular mà thôi. Nếu không có angular script thì trình duyệt sẽ in ra luôn “{{data}}”.

Bạn hãy thử điền bất kì cái gì bạn muốn vào ô text input. Và điều thần kì xảy ra ở chỗ: p.textContent thay đổi ngay khi input.value thay đổi ngay khi bạn chưa kịp nhấc ngón tay lên khỏi phím bấm. Hay chưa! Tất cả là nhờ có ng-model. Vậy ngModel là gì? Nó là một AngularJS directive (tôi sẽ nói về directives sau). Khi bạn gán nó vào một element nào, ngoài việc tạo định nghĩa một biến, thì trong một số trường hợp như đối với các <input> như trong ví dụ bên trên, thì nó sẽ nhận giá trị là value của chính các input. Vì vậy, nó là một công vụ vô cùng hữu hiệu để quan sát các <input>, cũng như giúp bạn tránh mất thời gian gõ bàn phím các kí tự “document.getElementById” hay “document.querySelector” mà chỉ cần dùng trực tiếp tên model luôn cho khỏe, mà lại đảm bảo tính chính xác cũng như tận dụng được tính “real-time” của nó. Thật là tiện lợi trăm bề.

Mặc dù tiêu đề bài và đoạn này là Two-way data binding, tức ràng buộc dữ liệu hai chiều, nhưng tôi chỉ đưa ra một chiều, là p.textContent chỉ listen một chiều theo input.value. Về chiều hướng ngược lại, tức input.value sẽ listen p.textContent, hiện tại còn yêu cầu kiến thức phần Controller. Vì vậy, tạm thời chúng ta dừng ở đây, và sẽ quay lại trong bài Controller.

4. Thông tin thêm về Angular String expression:

Ngoài việc trỏ tới biến được định nghĩa tên trong ng-model, String expression còn có công dụng khác. Chẳng hạn, <p>{{2+5}}</p> sẽ tương ứng với <p>7</p>, tức là nó tính toán cho bạn. Mặt khác, bạn có thể thực hiện thao tác concat vô cùng đơn giản. Chẳng hạn, <p>Hello, {{name}}. How are you?</p>, với giá trị của ng-model=’name’ là “EITGUIDE”, thì kết quả sẽ tương đương với <p>Hello, EITGUIDE. How are you?</p>. Tiện lợi hơn cả ES6 2015! Và String expression cũng khả dụng đối với Angular2+ luôn, nên bạn có thể thoải mái “nhồi nhét” biến trong thân một String mà không gặp trở ngại nào. Tuy nhiên, ngoài các tính toán ra thì String expressions chỉ sử dụng khi lấy giá trị của một ng-model ra mà thôi. Còn giá trị của một JS variable hay constant thì rất tiếc, không được. Vd:

Trong thời gian chờ đợi bài tiếp theo, bạn có thể tự do voọc vạch String expression để khám phá thêm các “khả năng tiềm ẩn” của chúng. Chúc các bạn vui vẻ.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.