Javascript lớp, instance và error

Tôi gặp tình huống thực tế trong lúc code javascript như bên dưới. Ghi lại ở đây để có dịp nhình lại hoặc giúp chút gì đó nếu ai gặp phải giống tôi(Dưới đây là tôi lượt bỏ để code ví dụ trở nên đơn giản dễ hiểu hơn).

Mô tả C1(Component 1), C2(Component 2)


Tôi có hai component C1, C2. Trong C1 sẽ có một thể hiện C2.

Code như bên dưới.

c1.js

(function ($) {
    function c1(options) {
        var _options = {//Default setting component
            module: ""
        }
        this.options = jQuery.extend(_options, options);//Merge setting from instance and default seting
        this.specialPage = false;//properties of class
    };

    c1.prototype.init = function () {//init function, this is registered some cases variable
        CONST: {
            MAX_INT: 2147483647
        }
        _event = $({});//trigger event object
        this.c2 = new c2(this.options);
        this.c2.init();//call the init method of component second
        this.$icon = jQuery(".htmlclass");//this is object registered jQuery object
        console.log(this.options, "done", this.$icon);//test logic console log to browser
    };
})(jQuery)

c2.js

(function ($) {
    function c2(options) {
        var _options = {
            module: ""
        };
        this.options = jQuery.extend(_options, options);
        specialPage: false;
    };
    c2.prototype = {
        _event: $({}),
        CONST: {
            MAX_INT: 2147483647
        },
        init: function () {
            console.log('c2 done');
        }
    }
})(jQuery)
---
Ở html page tôi sẽ triệu gọi như sau
<script>
        var options = {"module": "ABC" };
        var c1Instance = new c1(options);
        c1Instance .init();
        console.log(c1Instance .options.module, c1Instance .c2.specialPage)
    });
</script>
---> khi chạy sẽ xuất hiện lỗi như sau:

Uncaught ReferenceError: c1 is not defined

Sau khi khắc phục


c1.js

  function c1(options) {
    var _options = {
        module: ""
    }
    this.options = jQuery.extend(_options, options);
    this.specialPage = false;
};

c1.prototype.init = function () {
    CONST: {
        MAX_INT: 2147483647
    }
    _event = $({});
    this.c2 = new c2(this.options);
    this.c2.init();
    this.$icon = jQuery(".htmlclass");

    console.log(this.options, "done", this.$icon);
}

c2.js

function c2(options) {
    var _options = {
        module: ""
    };
    this.options = jQuery.extend(_options, options);
    specialPage: false;
};
c2.prototype = {
    _event: $({}),
    CONST: {
        MAX_INT: 2147483647
    },
    init: function () {
        console.log('c2 done');
    }
}
---
Ở html page tôi sẽ triệu gọi như sau
<script>
        var options = {"module": "ABC" };
        var c1Instance = new c1(options);
        c1Instance .init();
        console.log(c1Instance .options.module, c1Instance .c2.specialPage)
    });
</script>

Nguyên nhân - cách khắc phục:

Closure javascript, có nghĩa là ta định nghĩa c1 với clouse nên ra khỏi nó c1 trở nên undefined
Tips: Google search closure javascript

Phân tích trước khi viết javascript

Hình minh họa viết javascript
Hầu như ai viết web, động lẫn tĩnh đều viết được javascript. Nhưng nếu để viết cho ra trò(dạng viết tối ưu, chia nhỏ, không ôm đồm) thì có lẽ đém trên đầu ngón tay.

Tôi, ngày tháng lăn lốc chốn công sở, nay viết vài dòng nhằm ôn lại những gì đã viết và chia sẽ bà kon những gì tôi biết.

Để tiện cho việc mô tả điều tôi muốn nói, tôi tạm đưa ra một
Yêu cầu bài làm như sau:

Viết javaScript làm nhiệm vụ:
Suggest một danh sách item khi người dùng gõ vào textbox.(giống facebook gõ hiển thị danh sách xổ xuống,)
+ Mỗi item gồm có tiêu đề, biểu tượng
+ Khi click item này thì danh sách sẽ biến mất, và một item vừa chọn sẽ đưa vào mục DANH SÁCH ĐÃ CHỌN.
+ Danh sách đã chọn, người dùng có thể click icon x để bỏ chọn.
+ Danh sách xổ xuống, không tồn tại những item đã chọn.(Như vậy không tồn tại hai item giống nhau cho danh sách đã chọn)

Thông tin lập trình:
Ví dụ: a---> a, ba, banana, sang, lang, ...
Sau đó người dùng chọn một item từ danh sách đó để đưa vào một <ul> nhằm ghi nhận những gì đã chọn
Khi chọn xong, kêt thúc và trở lại trạng thái sẵn sàng như  mới vào page.

Phân tích yêu cầu

Có hai thứ cần viết.
+ Component SuggestItem (truy vấn dữ liệu từ server, trả về dạng json), sau đó hiển thị thành danh sách xổ xuống

+ Component thứ 2 ItemListSelected là ghi nhận lại những gì đã chọn từ C1 (Component SuggestItem)
+ Như vậy component 1 không quan tâm ai sử dụng mình và làm gì, mà chỉ cung cấp 1 trigger là "selected", tức khi user click item từ danh sách, sẽ lấy ra một item thông qua trigger "selected"
+ Component thứ 2 thì luôn lắng nghe khi nào thì trigger selected sẽ firing ra, để đón nhận và làm việc của mình.
--> Cách viết này nhằm mục đích:
 PHÂN CHIA NHIỆM VỤ
VÀ KHÔNG PHỤ THUỘC VÀO ĐỐI TƯỢNG SẼ SỬ DỤNG LÀ AI
--> Component 2 cũng có thể cung cấp các trigger VD: Change để tương lai có thể sử dụng nó.

Tiêu chuẩn kỹ thuật:
+ Tất cả component không được phụ thuộc vào đối tượng sử dụng
+ Chống xss
+ Tốc độ nhanh(không quá 3 giây cho mỗi lần hiển thị)
+ Không viết cho một csdl cụ thể nào
+ Đối với component 1:
  - Dùng các phím lên, xuống, enter, và esc để làm phím tắt
  - Dùng keyword "a" để làm shortcut add

Tiếp cận vấn đề theo hướng module hóa


1/ Định nghĩa component SuggestItem và phân chia nhiệm vụ


+ Nhận vô string,
+ Gửi dữ liệu về server xử lý
+ Nhận kết quả xử lý trả về từ server JsonObject [{id:integer, title:string, iconPath:string, reserverField:string}]
(mảng json)
+ Xử lý để hiển thị dạng list (ul, li)
+ Bind sẵn sự kiện khi click sẽ trigger ra một event đặt tên là Selected

2/ Định nghĩa component ItemListSelected


+ Đăng ký  một textbox để nhận dữ liệu dạng plan text được end-user nhập vô.
+ Gửi dữ liệu qua component SuggestItem để xử lý
+ Đăng ký  một sự kiện để lắng nghe xem bên control kia có trigger ra item nào không.
+ Render lại item theo dạng <ul><li>title</li></ul>

3/ Coding

Step 0:
Tạo một trang html Demo.html và có nội dung như sau

<!DOCTYPE html>
<html>

<head>
    <title> Demo Javascript module</title>
</head>

<body>
    <div class="item-picker">
        <div class="item-selected">
        </div>
        <div class="input-item-picker">
            <input type="text" class="input-picker" />
            <span class="input-item-add-icon"></span>
        </div>
    </div>
</body>

</html>


Step 1:
Tạo file javascript mang tên SuggestItem.js và gõ vô như sau

(function($) {

    var SuggestItem = function(options) {
        var default_options = {
            url: "/Commands/ajaxCommand.aspx",
            numberRowDisplay: 10, //Giới hạn số item hiển thị trên danh sách
            target: "" //HTML class, id mà component nhận dữ liệu
        };
        this.options = $.extend(default_options, options); //Dùng để trộn lẫn setting mặt định và setting được định nghĩa cho từng nơi gọi
    };

    SuggestionItem.prototype = { //Những gì viết trong prototype thì được phép truy cập công khai
        HTML_Template: {}, //Chứa đựng các template sẽ làm việc.
        _event: $({}), // tập hợp các event sống chung với jQuery khi trigger
        init: function() {
            //gọi các hàm thành viên phục vụ cho mục đích contructor
            this.createComponent(); //dăng ký các html vào document
            this.cacheElement(); // nhớ lại các html element để nội bộ component này làm việc
            this.bindEvent(); //gán các event cho html
        },
        _handleOnClickItem: function(event) {

            this._event.trigger("selected", this.getItemSelected(event));
        },
        on: function(event, fn) {
            this._event.on(event, fn);
        },
        searchItem: function(params) {},

    };

})(jQuery);

Bên component ItemListSelected
ItemListSelected.js
(function($) {
    init: function() {

        this.suggestItem = new SuggestItem({
            url: this.options.url
        });
        this.suggestItem.init();
        this.bindEvents();
    },

    bindEvents: function() {
        var self = this;
        this.suggestItem.on("selected", $.proxy(this._onSelectedSuggestItem, this)); //Khi component SuggestItem trigger sẽ trả về một item được chọn. Từ item này component sẽ build lại theo mục đích muống sử dụng.
    }
})(jQuery);

Popular Posts

Like us on Facebook

Flickr Images