12/08/2018, 13:48

Thêm và xóa field với Rails Nested Forms and AngularJS

Giới thiệu Việc làm nested form trong rails là khá đơn giản, khi chúng được hỗ trợ khá nhiều. Và có khá nhiều bài viết mẫu và ví về việc thêm hay xóa bớt các field được viết bằng jquery. Nhưng giả sử bạn không muốn dùng jquery vì lo ngại về tốc độ xử lý, bạn nghĩ ngay đến angularJS nhưng lại ...

Giới thiệu

Việc làm nested form trong rails là khá đơn giản, khi chúng được hỗ trợ khá nhiều. Và có khá nhiều bài viết mẫu và ví về việc thêm hay xóa bớt các field được viết bằng jquery.

Nhưng giả sử bạn không muốn dùng jquery vì lo ngại về tốc độ xử lý, bạn nghĩ ngay đến angularJS nhưng lại chưa biết cách sử dụng nó kết hợp với Rails Nested Forms. Trong phần này, chúng ta sẽ cùng làm ví dụ nhỏ dưới đây để tìm hiểu cách dựng form nested với AngularJS

Tạo model

Giả sử ta có 2 model: Plan và Poll. Với Plan là cha, còn Poll là con. Trong model Plan ta sẽ khai báo: accepts_nested_attributes_for :polls

# app/models/plan.rb
class Plan < ActiveRecord::Base
  has_many :polls

  accepts_nested_attributes_for :polls
end
# app/models/poll.rb
class Poll < ActiveRecord::Base
  belongs_to :plan
end

Tạo controller

Trong controller của Plan ta sẽ build sẵn 1 poll mặc định ban đầu.

# app/controllers/plans_controller.rb
class PlansController < ApplicationController
  def new
    @plan = Plan.new
    @poll = @plan.polls.build
  end

  def create
    @plan = Plan.new plan_params
    @plan.save
  end
end

View

# app/views/plans/new.html.erb
<div ng-app>
  <%= form_for @plan do |form| %>
    <div ng-controller="PlanCtrl as vm" ng-init="vm.polls = [{title: '}]">
      <div ng-repeat="poll in vm.polls">
        <%= form.fields_for :polls, @poll, child_index: '{{$index}}' do |poll_form| %>
          <%= poll_form.text_field :title, id: 'plan_poll_{{$index}}', "ng-model": "poll.title" %>
        <% end %>
        <a href="#" ng-click="vm.remove($index)" ng-show="vm.isRemovable()">Remove</a>
      </div>
      <a href="#" ng-click="vm.add()">Add</a>
    </div>
  <% end %>
</div>

Ta khai báo 1 mảng polls = [{title: '}] để chạy vòng lặp. Mỗi lần thêm hoặc xóa field là thêm hoặc xóa 1 phần tử của mảng này.

AngularJS controller

Các hàm thêm và xóa field được viết trong AngularJS controller.

// app/assets/javascripts/plans.js
function PlanCtrl() {
  vm.isRemovable = function() {
    return vm.polls.length > 1;
  };

  vm.add = function() {
    vm.polls.push({title: '});
  };

  vm.remove = function(index) {
    vm.polls.splice(index, 1);
  };
}

Giải thích các hàm:

$scope.isRemovable = function() {
  return $scope.polls.length > 1;
};

Hàm isRemovable() để kiểm tra xem field có thể xóa hay không. Khi số phần tử của poll lớn hơn 1 thì có thể xóa.

$scope.add = function() {
  $scope.polls.push({title: '});
};

Hàm add() để thêm phần tử vào poll, tạo thêm 1 lần lặp, đồng nghĩa với việc thêm field.

$scope.remove = function(index) {
  $scope.polls.splice(index, 1);
};

Hàm remove() để xóa phần tử trong poll, bỏ đi 1 lần lặp, đồng nghĩa với việc xóa field.

0