Сайт веб-разработчика Николая Семенцова

Партнер компании 1с-битрикс

Ajax фильтры для каталога , с возможностью добавлять в закладки браузера

При создании интернет-магазин часто используются фильтры товара по характеристикам , пользователей раздражает когда при изменение свойств поиска, идет перезагрузка страницы, давай те исправим это положение и сделаем полноценный фильтр на ajax .

Мы будем использовать хэш что бы была возможность ложить ссылку в закладку, кидать другу и использовать историю для перехода назад к параметрам поиска .

Делать мы будем все это чудо с помощью jquery , загрузим его с гугла .

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>

Использовать я буду стандартный модуль каталог , в нем нам надо будет изменить шаблон вывода фильтра catalog/castlerock/castlerock.catalog.filter/.default/template.php обернув его в тег с классом catalog-filter и добавить туда два скрых поля с параметрами раздела и инфоблока .

<div class="catalog-filter">
 
    <form name="<?echo $arResult["FILTER_NAME"]."_form"?>" action="<?echo $arResult["FORM_ACTION"]?>" method="get">
    <!-- скрытые поля для передачи параметров раздела и инфоблока -->
    <input type="hidden" name='AJAXSELECTION_IBLOCK_ID' value='<?=$arResult["IBLOCK_ID"];?>' />
    <input type="hidden" name='AJAXSELECTION_SECTION_CODE' value='<?=$arResult["SECTION_CODE"];?>' />
    <div class="catalog-item-filter<?if ($arResult['IS_FILTERED']):?> filter-active<?endif;?>">
        <div class="catalog-item-filter-body" id="catalog_item_filter_body">
            <b class="r1"></b>
            <div class="catalog-item-filter-body-inner">
                <table cellspacing="0" class="catalog-item-filter" id="catalog_item_filter_table">
                <tbody>
                    <?foreach($arResult["ITEMS"] as $arItem):?>
                        <?if(!array_key_exists("HIDDEN", $arItem)):?>
                            <tr>
                                <td class="field-name"><?=$arItem["NAME"]?>:</td>
                                <td class="field-control"><span class="filter-<?=$arItem["TYPE"]?>"><?=$arItem["INPUT"]?></span></td>
                            </tr>
                        <?endif?>
                    <?endforeach;?>
                </tbody>
                <tfoot>
                    <tr>
                        <td class="field-name"> </td>
                        <td class="field-control"><input type="submit" name="set_filter" value="<?=GetMessage("IBLOCK_SET_FILTER")?>" /><input type="hidden" name="set_filter" value="Y" /> <input type="submit" name="del_filter" value="<?=GetMessage("IBLOCK_DEL_FILTER")?>" /></td>
                    </tr>
                </tfoot>
                </table>
            </div>
            <b class="r1"></b>
        </div>
    </div>
    </form>
</div>

Так же надо в шаблоне фильтра catalog/castlerock/castlerock.catalog.filter/.default/ добавить файл result_modifier.php и в нем назначить вывод в массив двух переменных 

<?if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();
 
$arResult['IBLOCK_ID'] = $arParams["IBLOCK_ID"];
$arResult['SECTION_CODE'] = $arParams["SECTION_CODE"];
 
?>

В файле вывода фильтра и элементов раздела надо, добавить в модуль фильтра еще два параметра (SECTION_CODE и IBLOCK_ID) обернуть вывод элементов разделе в тег с классом list-selection-element,

<?if($arParams["USE_FILTER"]=="Y"):?>
    <?$APPLICATION->IncludeComponent(
        "castlerock:castlerock.catalog.filter",
        "",
        Array(
            "IBLOCK_TYPE" => $arParams["IBLOCK_TYPE"],
            "IBLOCK_ID" => $arParams["IBLOCK_ID"],
            "FILTER_NAME" => '',
            "SECTION_ID" => $arResult["VARIABLES"]["SECTION_ID"],
            "SECTION_CODE" => $arResult["VARIABLES"]["SECTION_CODE"],
            "FIELD_CODE" => $arParams["FILTER_FIELD_CODE"],
             "PROPERTY_CODE" => $filter_property,
            "PRICE_CODE" => $arParams["FILTER_PRICE_CODE"],
            "OFFERS_FIELD_CODE" => $arParams["FILTER_OFFERS_FIELD_CODE"],
            "OFFERS_PROPERTY_CODE" => $arParams["FILTER_OFFERS_PROPERTY_CODE"],
            "CACHE_TYPE" => $arParams["CACHE_TYPE"],
            "CACHE_TIME" => $arParams["CACHE_TIME"],
            "CACHE_GROUPS" => $arParams["CACHE_GROUPS"],
        ),
        $component
    );
    ?>
 
<?endif?>
<div class="list-selection-element">
<?$APPLICATION->IncludeComponent(
    "castlerock:castlerock.catalog.section",
    "",
    Array(
        "IBLOCK_TYPE" => $arParams["IBLOCK_TYPE"],
        "IBLOCK_ID" => $arParams["IBLOCK_ID"],
        "ELEMENT_SORT_FIELD" => $sort,//$arParams["ELEMENT_SORT_FIELD"],
        "ELEMENT_SORT_ORDER" => $sort_order,//$arParams["ELEMENT_SORT_ORDER"],
         "PROPERTY_CODE" => $arParams["LIST_PROPERTY_CODE"],
        "META_KEYWORDS" => $arParams["LIST_META_KEYWORDS"],
        "META_DESCRIPTION" => $arParams["LIST_META_DESCRIPTION"],
        "BROWSER_TITLE" => $arParams["LIST_BROWSER_TITLE"],
        "INCLUDE_SUBSECTIONS" => $arParams["INCLUDE_SUBSECTIONS"],
        "BASKET_URL" => $arParams["BASKET_URL"],
        "ACTION_VARIABLE" => $arParams["ACTION_VARIABLE"],
        "PRODUCT_ID_VARIABLE" => $arParams["PRODUCT_ID_VARIABLE"],
        "SECTION_ID_VARIABLE" => $arParams["SECTION_ID_VARIABLE"],
        "FILTER_NAME" => $arParams["FILTER_NAME"],
        "DISPLAY_PANEL" => $arParams["DISPLAY_PANEL"],
        "CACHE_TYPE" => $arParams["CACHE_TYPE"],
        "CACHE_TIME" => $arParams["CACHE_TIME"],
        "CACHE_FILTER" => $arParams["CACHE_FILTER"],
        "CACHE_GROUPS" => $arParams["CACHE_GROUPS"],
        "SET_TITLE" => $arParams["SET_TITLE"],
        "SET_STATUS_404" => $arParams["SET_STATUS_404"],
        "DISPLAY_COMPARE" => $arParams["USE_COMPARE"],
        "PAGE_ELEMENT_COUNT" => $arParams["PAGE_ELEMENT_COUNT"],
        "LINE_ELEMENT_COUNT" => $arParams["LINE_ELEMENT_COUNT"],
        "PRICE_CODE" => $arParams["PRICE_CODE"],
        "USE_PRICE_COUNT" => $arParams["USE_PRICE_COUNT"],
        "SHOW_PRICE_COUNT" => $arParams["SHOW_PRICE_COUNT"],
 
        "PRICE_VAT_INCLUDE" => $arParams["PRICE_VAT_INCLUDE"],
 
        "DISPLAY_TOP_PAGER" => $arParams["DISPLAY_TOP_PAGER"],
        "DISPLAY_BOTTOM_PAGER" => $arParams["DISPLAY_BOTTOM_PAGER"],
        "PAGER_TITLE" => $arParams["PAGER_TITLE"],
        "PAGER_SHOW_ALWAYS" => $arParams["PAGER_SHOW_ALWAYS"],
        "PAGER_TEMPLATE" => $arParams["PAGER_TEMPLATE"],
        "PAGER_DESC_NUMBERING" => $arParams["PAGER_DESC_NUMBERING"],
        "PAGER_DESC_NUMBERING_CACHE_TIME" => $arParams["PAGER_DESC_NUMBERING_CACHE_TIME"],
        "PAGER_SHOW_ALL" => $arParams["PAGER_SHOW_ALL"],
 
        "OFFERS_CART_PROPERTIES" => $arParams["OFFERS_CART_PROPERTIES"],
        "OFFERS_FIELD_CODE" => $arParams["LIST_OFFERS_FIELD_CODE"],
        "OFFERS_PROPERTY_CODE" => $arParams["LIST_OFFERS_PROPERTY_CODE"],
        "OFFERS_SORT_FIELD" => $arParams["OFFERS_SORT_FIELD"],
        "OFFERS_SORT_ORDER" => $arParams["OFFERS_SORT_ORDER"],
        "OFFERS_LIMIT" => $arParams["LIST_OFFERS_LIMIT"],
 
        "SECTION_ID" => $arResult["VARIABLES"]["SECTION_ID"],
        "SECTION_CODE" => $arResult["VARIABLES"]["SECTION_CODE"],
        "SECTION_URL" => $arResult["FOLDER"].$arResult["URL_TEMPLATES"]["section"],
        "DETAIL_URL" => $arResult["FOLDER"].$arResult["URL_TEMPLATES"]["element"],
 
        "COMPARE_URL" => $arResult["FOLDER"].$arResult["URL_TEMPLATES"]["compare"],
        "COMPARE_NAME" => $arParams["COMPARE_NAME"],
 
        "DISPLAY_IMG_WIDTH"     =>    $arParams["DISPLAY_IMG_WIDTH"],
        "DISPLAY_IMG_HEIGHT" =>    $arParams["DISPLAY_IMG_HEIGHT"],
 
        "SHARPEN" => $arParams["SHARPEN"],
 
        "ADD_SECTIONS_CHAIN" => "Y"
    ),
    $component
);
?>
</div>

Собственно теперь напишем сам скрипт на js , первая функция необходима для того что бы заполнять форму когда человек заходим с хэшем в строке, вторая функция для того что бы сократить количество кода для каждого ajax запроса, дальше функции непосредственно для ajax запросов.

/* Первая функция это тоже самое что  serialize() только наоборот , она заполняет  форму по данным из массива. */
(function($)
{
    $.fn.deserialize = function(data, clearForm)
    {
        this.each(function(){
            deserialize(this, data, !!clearForm);
        });
    };
 
    function deserialize(element, data, clearForm)
    {
        var splits = decodeURIComponent(data).split('&'),
            i = 0,
            split = null,
            key = null,
            value = null,
            splitParts = null;
 
        if (clearForm)
        {
            $('input[type="checkbox"],input[type="radio"]', element).removeAttr('checked');
            $('select,input[type="text"],input[type="password"],input[type="hidden"],textarea', element).val('');
        }
 
        while(split = splits[i++])
        {
            splitParts = split.split('=');
            key = splitParts[0] || '';
            value = (splitParts[1] || '').replace(/\+/g, ' ');
 
            if (key != '')
            {
                $('input[type="checkbox"][name="'+ key +'"][value="'+ value +'"],input[type="radio"][name="'+ key +'"][value="'+ value +'"]', element).attr('checked', 'checked');
                $('select[name="'+ key +'"],input[type="text"][name="'+ key +'"],input[type="password"][name="'+ key +'"],input[type="hidden"][name="'+ key +'"],textarea[name="'+ key +'"]', element).val(value);
            }
        }
    }
 
})(jQuery);
 
/* Function for ours ajax inquiry  */
function ajaxpostshow(urlres, datares, wherecontent ){
       $.ajax({
           type: "POST",
           url: urlres,
           data: datares,
           dataType: "html",
           beforeSend: function(){
                var elementheight = $(wherecontent).height();
                $(wherecontent).prepend('<div class="ajaxloader"></div>');
                $('.ajaxloader').css('height', elementheight);
                $('.ajaxloader').prepend('<img class="imgcode" src="/js/ajax/ajax-loader.gif">');
            },
           success: function(fillter){
                $(wherecontent).html(fillter);
           }
      });
}
 
  /* Sending ajax inquiry with values of filters, formation of value of filters */
   $(".catalog-filter input, .catalog-filter select").live("change", function(){
       var arrayform = $(".catalog-filter form").serialize();
       location.hash = arrayform;
       var ajaxfillter = document.location.hash.substr(1);
       ajaxpostshow("/include/ajax/fillter-element.php", ajaxfillter, ".list-selection-element" );
   });
 
  /* Conclusion of values from the filter with the help ajax and hashe */
  $(document).ready(function(){
     var hash = window.location.hash.substr(1);
     if(hash != "") {
         var ajaxfillter = document.location.hash.substr(1);
         $(".catalog-filter form").deserialize(ajaxfillter, true);
         ajaxpostshow("/include/ajax/fillter-element.php", ajaxfillter, ".list-selection-element" );
     }
  });
/* Event for ajax paginal navigation */
   $(".ajax-navigation a").live("click", function(){
         var pagenum = $(this).attr('id');
         var arrayform = $(".catalog-filter form").serialize();
         var ajaxfillter = arrayform + '&' + pagenum;
         location.hash = ajaxfillter;
         ajaxpostshow("/include/ajax/fillter-element.php", ajaxfillter, ".list-selection-element" );
         return false;
   });

Теперь напишем сам обработчик для вывод элементов каталога, постраничной навигации , его можно будет сделать любой сложности в зависимости от поступающих параметров в запросе $_POST

<?
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
/* We change the coding and the arriving parametre of a name */
$_POST['arrFilter_ff']['NAME'] = iconv("UTF-8", "WINDOWS-1251", $_POST['arrFilter_ff']['NAME']);
 
CModule::IncludeModule("sale");
CModule::IncludeModule("catalog");
CModule::IncludeModule("iblock");
 
if($_POST['ajaxpage']) {
  $ajaxpage = $_POST['ajaxpage'];
}
else {
  $ajaxpage = 1;
}
 
 
$arOrder = Array("SORT"=>"ASC");
$arFilter = array();
/* We bring section parametres in the filter */
foreach($_POST as $key => $value) {
 
  if(substr($key, 0, 14) == 'AJAXSELECTION_'){
    $key = substr($key, 14);
    $arFilter[$key] = $value;
  }
   /* if key  arrFilter_ff we form logic creation of a file */
  elseif($key == 'arrFilter_ff'){
    foreach($value  as $key2 => $value2) {
        $arFilter[$key2] = $value2;
    }
  }
  /* we form file */
  elseif($key == 'arrFilter_cf') {
    $arFilter[] = array(
        ">=CATALOG_PRICE_1" => $value[1]['LEFT'],
        "<=CATALOG_PRICE_1" => $value[1]['RIGHT'],
    );
  }
  /* if key  arrFilter_pf we form logic creation of a file */
  elseif($key == 'arrFilter_pf'){
     /*  $value file we form file */
     foreach($value  as $key2 => $value2) {
      /* check if  $value2  file  that we form a new file */
        if(is_array($value2)) {
             foreach($value2  as $key3 => $value3) {
                 $arFilter['PROPERTY_'.$key2] = $value3;
             }
        }
      /* if $value2 not file that we form file  for property */
        else {
           $arFilter['PROPERTY_'.$key2] = $value2;
        }
     }
  }
 
}
 
/* we form file order */
 
if($_POST['sort'] && $_POST['by']){
    $arOrder = array ($_POST['sort'] => $_POST['by']);
}
 
/* we form file samples */
$arSelect = Array("ID", "NAME", "PREVIEW_TEXT", "PREVIEW_PICTURE", "DETAIL_PICTURE", "CATALOG_GROUP_1", "PROPERTY_CML2_LINK.ID" );
 
/* we realise sample elements infoblock */
$res = CIBlockElement::GetList( $arOrder , $arFilter, false , Array("nPageSize"=>$_POST['pagecount'], "iNumPage"=>$ajaxpage , "bShowAll"=> false), $arSelect);
 
?>
 
<div class="catalog-item-list">
<?
while($ar_fields = $res->GetNext()){ ?>
    <?
    /* We find the adhered elements  */
    $arOrderPrice = array('sort' => 'asc');
    $arFilterPrice = Array("IBLOCK_TYPE" => "offers", "PROPERTY_CML2_LINK" => $ar_fields['ID']);
    $arSelectPrice = Array("ID", "NAME", "IBLOCK_ID", "CATALOG_GROUP_1", "PROPERTY_CML2_ATTRIBUTES" );
    $resPrice = CIBlockElement::GetList( $arOrderPrice , $arFilterPrice, false , Array(), $arSelectPrice);
 
    $attributes = array();
    $i = 1;
    while($ar_fieldsPrice = $resPrice->GetNext()){
       if($i == 1) {
          $basketFirst = $ar_fieldsPrice['ID'];
       }
       $attributes[] = array("ID" =>$ar_fieldsPrice['ID'], "PROP_VALUE" => $ar_fieldsPrice['PROPERTY_CML2_ATTRIBUTES_VALUE']) ;
       $i++ ;
    }
    ?>
 
 
    <div class="catalog-item" >
        <div class="catalog-item-info">
            <div class="catalog-item-image">
                <? echo CFile::ShowImage($ar_fields['DETAIL_PICTURE'], 75, 100, "border=0", $ar_fields['CODE']."/");?>
            </div>
            <div class="catalog-item-desc">
                <div class="catalog-item-title">
                    <a href="<?=$ar_fields['CODE'];?>/"><?=$ar_fields['NAME']; ?></a>
                </div>
                <div class="catalog-item-preview-text">
                    <?=$ar_fields['PREVIEW_TEXT']; ?>
                </div>
                <div class="catalog-item-price">
                     <span class="catalog-item-price"><?=$ar_fields['CATALOG_PRICE_1']; ?> руб</span>
                </div>
            </div>
        </div>
 
        <div class="catalog-item-links">
            <? if($attributes[0]['PROP_VALUE']):?>
                <label>Размер</label>
                <select>
                <? foreach($attributes as $attribute):?>
                    <option value="<? echo $attribute['ID'];?>"><? echo $attribute['PROP_VALUE'];?></option>
                <? endforeach;?>
                </select>  <br />
                <a id="ajaxaction=add&ajaxaddid=<?=$basketFirst;?>" rel="nofollow" class="catalog-item-buy input-basket-submit input-basket-submit-property" href="?action=ADD2BASKET&id=<?=$basketFirst;?>">В корзину</a>
            <? else:?>
                <a id="ajaxaction=add&ajaxaddid=<?=$basketFirst;?>" rel="nofollow" class="catalog-item-buy input-basket-submit" href="?action=ADD2BASKET&id=<?=$basketFirst;?>">В корзину</a>
            <? endif;?>
 
        </div>
 
    </div>
 
    <div class="catalog-item-separator"></div>
<?} ?>
</div>
<?
/* we realise реализуем paginal navigation  */
 
$NAV_STRING = $res->GetPageNavStringEx($navComponentObject, "", 'ajaxarrows');
 
echo $NAV_STRING;
?>

Для постраничной навигации я сделал свой шаблон для того что бы работал ajax , назвал я его ajaxarrow , в нем я добавил только к ссылкам id с номером страницы id="ajaxpage=<?=$sNextcount;?>" и класс ajax-navigation обертыш этого шаблона.

Вот собственно и все .



Опубликовано: 17 Августа 2011




Помогла заметка? Жмите кнопки ниже


ВКонтакт Facebook Google Plus Одноклассники Twitter Яндекс Livejournal Liveinternet Mail.Ru





comments powered by Disqus

Партнер 1c-bitrix