2012-01-31 94 views
1

我正在構建一個需要列出產品類別和子類別的應用程序。這是使用Deferred對象的正確方法嗎?

當用戶選擇一個類別時,與該類別相關的子類別將從服務器加載ajax,但前提是它們以後未加載(在這種情況下,它們是從DOM加載的)。

代碼:http://jsbin.com/abijad/edit#javascript,html

var $form = $('#new-product-form'); 

$form.on('change', 'select.product-categories', function(e) { //I'm using event delegation for a future feature... 

    getSubCategories($(this).val()).done(function($subCategoriesEl){ 
    $form.find('select.product-subcategories').not($subCategoriesEl).hide(); 
    $subCategoriesEl.show(); 
    }); 

}); 

var getSubCategories = function(categoryId) { 

    var dfd = $.Deferred(), 
     $alreadyisLoaded = $form.find('select.product-subcategories').map(function(idx, el){ 
     if(parseInt($(this).data('category'), 10) === parseInt(categoryId, 10)){ 
      return el; 
      } 
     }); 

     if($alreadyisLoaded.length > 0){ //don't request subCategories that already are loaded 
     console.log('SubCategory loaded from DOM'); 
     dfd.resolve($alreadyisLoaded); 
     } else { 
     var subCategoriesHtml = '<select data-category="' + categoryId + '" class="product-subcategories">'; 

     $.get('/', { //The ajax request will only be simulated 
      categoryId : categoryId 
     }, function (result) { 
      //simulate success :X 
      result = {"status":1,"data":[{"name":"Sub-Category I","id":1},{"name":"Sub-Category II","id":2},{"name":"Sub-Category III","id":3}]}; 

      console.log('SubCategory loaded with Ajax'); 

      if(result.status === 1) { //Success 

      for(var subCategoryInfo in result.data) { 
       if(result.data.hasOwnProperty(subCategoryInfo)){ 
       subCategoriesHtml += '<option value="' + result.data[subCategoryInfo].id + '">'; 
       subCategoriesHtml += result.data[subCategoryInfo].name + '</option>'; 
       } 
      } 

      subCategoriesHtml += '</select>'; 

      var $subCategories = $(subCategoriesHtml).hide().appendTo($form); 

      dfd.resolve($subCategories); 
      } else { 
      dfd.reject(); 
      } 
     }); 
     } 

     return dfd.promise(); 

}; 

<form id="new-product-form"> 
    <select class="product-categories"> 
    <option value="1">Category I</option> 
    <option value="2">Category II</option> 
    <option value="3">Category III</option> 
    <option value="4">Category IV</option> 
    <option value="5">Category V</option> 
    </select> 
    <select data-category="1" class="product-subcategories"> 
    <option value="1">SubCategory I</option> 
    <option value="2">SubCategory II</option> 
    <option value="3">SubCategory III</option> 
    <option value="4">SubCategory IV</option> 
    <option value="5">SubCategory V</option> 
    </select> 
</form> 

因爲代碼快滿了回調這裏和那裏,我決定使用jQuery的Deferred對象,但我不知道這是否是正確的實施。有人可以告訴我,我做了正確的事情,還是應該做不同的事情?

+0

除了鏈接之外,請在問題中包含相關代碼。目標是儘可能保持SO自足。如果外部網站消失,問題仍然應該是相關的。 – 2012-01-31 01:41:49

+0

@JamesMontagne請參閱編輯。 – JCM 2012-01-31 01:55:38

+0

我只會緩存延遲對象,並重新構建每個後續更改的選項,以避免最終在非常大的類別/子類別情況下有大量隱藏的元素,但除此之外,您擁有的將作爲只要元素的數量不會太大。 – 2012-01-31 01:57:52

回答

1

我沒有看到任何明顯不正確的東西。總而言之,您正在以正確的方式使用延遲:抽象出您的方法可能具有雙重同步性。這就是說,如果這是代碼出現在我的代碼庫中,這就是我將如何寫它。要點是:不要在數組上使用for in,使用數組構建字符串,命名和間距一致,以及其他簡潔的JS首選項。這些都是口味的問題,所以否則,良好的工作:

(function() { 
    var getSubCategories = function (categoryId) { 
     categoryId = +categoryId; 

     return $.Deferred(function (dfd) { 

      var isLoaded = form.find('select.product-subcategories') 
       .map(function (index, el) { 
        if (+$(this).data('category') === categoryId) { 
         return el; 
        } 
       }), 
       markup = [ ]; 

      if (isLoaded.length) { 
       console.log('SubCategory loaded from DOM'); 
       dfd.resolve(isLoaded); 
      } else { 
       markup.push('<select data-category="' + categoryId + '" class="product-subcategories">'); 

       var request = $.ajax({ 
        url: '/', 
        data: { categoryId: categoryId }  
       }); 

       request.done(function (result) { 
        //simulate success :X 
        result = {"status":1,"data":[{"name":"Sub-Category I","id":1},{"name":"Sub-Category II","id":2},{"name":"Sub-Category III","id":3}]}; 

        var status = result.status, 
         data = result.data, 
         i = 0, 
         il = data.length, 
         current; 

        console.log('SubCategory loaded with Ajax'); 

        if (status !== 1 || !data) { 
         dfd.reject(); 
         return; 
        } 

        for (current = data[ i ]; i < il; i++) { 
         markup.push('<option value="' + current.id + '">'); 
         markup.push(current.name + '</option>'); 
        } 

        markup.push('</select>'); 

        dfd.resolve($(markup.join('')).hide().appendTo(form)); 
       }); 
      } 

     }).promise(); 
    }; 

    var form = $('#new-product-form') 
     .on('change', 'select.product-categories', function (e) { 
      getSubCategories($(this).val()) 
       .done(function(el) { 
        form.find('select.product-subcategories') 
         .not(el) 
          .hide() 

        el.show(); 
       }); 
     }); 
}); 

作爲一個側面說明,只是想培養你沒有問題的任何處理,如果AJAX請求失敗。在這種情況下,您需要reject,並確保您編寫fail方法。只是一個頭。

+0

感謝您的頭。只有一個問題,用一個加號前置變量將其轉換爲整數? – JCM 2012-01-31 10:40:52

+0

使用JavaScript一元加運算符嘗試將值轉換爲數字,如果它尚未。這很容易和快速:https://developer.mozilla.org/en/JavaScript/Reference/Operators/Arithmetic_Operators#section_6 – Eli 2012-01-31 14:41:14

相關問題