Не получается корректно интегрировать подсказки на страницу оформления заказа интернет-магазина на CS-Cart
Добрый день!
Не получается корректно встроить код с вашими подсказками на страницу оформления заказа моего интернет-магазина (на CS-Cart).
В ходе попыток и экспериментов:
а) Закачал файлы, подключаемые в вашем jQuery-плагине себе на сервер;
б) Создал такого Франкенштейна:
<script class="cm-ajax cm-ajax-force cm-ajax-full-render" type="text/javascript" src="/app/dadata/jquery/1.10.2/jquery.min.js" data-no-defer></script>
<script class="cm-ajax cm-ajax-force cm-ajax-full-render" type="text/javascript" src="/app/dadata/dist/js/jquery.suggestions.min.js" data-no-defer></script>
<link class="cm-ajax cm-ajax-force cm-ajax-full-render" rel="stylesheet" href="/app/dadata/dist/css/suggestions.min.css" data-no-defer>
<script class="cm-ajax cm-ajax-force" type="text/javascript" data-no-defer>
/**
* Показывает индекс в отдельном поле
*/
function showPostalCode(suggestion) {
$("#elm_29").val(suggestion.data.postal_code);
}
/**
* Очищает индекс
*/
function clearPostalCode(suggestion) {
$("#elm_29").val("");
}
function join(arr /*, separator */ ) {
var separator = arguments.length > 1 ? arguments[1] : ", ";
return arr.filter(function(n) {
return n
}).join(separator);
}
function makeAddressString(address) {
if (address.settlement) {
return join([
address.city,
address.settlement
])
} else {
return join([
address.city,
])
}
}
function formatResult(value, currentValue, suggestion) {
var addressValue = makeAddressString(suggestion.data);
suggestion.value = addressValue;
return addressValue;
}
function formatSelected(suggestion) {
var addressValue = makeAddressString(suggestion.data);
return addressValue;
}
var
token = "63aca8e5a32834498b49fadbbbc3d8fd69811ec4",
type = "ADDRESS",
$city = $("#elm_23"),
$street = $("#elm_19");
// город и населенный пункт
$city.suggestions({
token: token,
type: type,
hint: false,
bounds: "city-settlement",
formatResult: formatResult,
formatSelected: formatSelected,
onSelect: showPostalCode,
onSelectNothing: clearPostalCode
});
// улица
$street.suggestions({
token: token,
type: type,
hint: false,
bounds: "street-house",
constraints: $city,
onSelect: showPostalCode,
onSelectNothing: clearPostalCode
});
</script>
В CS-Cart страница оформления заказа состоит из четырех шагов - регистрация/авторизация (шаг 1), адрес доставки/адрес плательщика (шаг 2), выбор способа доставки, выбор способа оплаты. При загрузке страницы попадаешь на один из этих четырех шагов (в зависимости от заполненности профиля и сохраненных кук), остальные три шага подгружаются через ajax.
Соответственно, вставил этот код в шаблон второго шага, получилось следующее:
{if $show_email}
<div class="ty-control-group">
<label for="{$id_prefix}elm_email" class="cm-required cm-email">{__("email")}<i>*</i></label>
<input type="text" id="{$id_prefix}elm_email" name="user_data[email]" size="32" value="{$user_data.email}" class="ty-input-text {$_class}" {$disabled_param} />
</div>
{else}
{if $profile_fields.$section}
{if $address_flag}
<div class="ty-profile-field__switch ty-address-switch clearfix">
<div class="ty-profile-field__switch-label">{if $section == "S"}{__("shipping_same_as_billing")}{else}{__("text_billing_same_with_shipping")}{/if}</div>
<div class="ty-profile-field__switch-actions">
<input class="radio cm-switch-availability cm-switch-inverse cm-switch-visibility" type="radio" name="ship_to_another" value="0" id="sw_{$body_id}_suffix_yes" {if !$ship_to_another}checked="checked"{/if} /><label for="sw_{$body_id}_suffix_yes">{__("yes")}</label>
<input class="radio cm-switch-availability cm-switch-visibility" type="radio" name="ship_to_another" value="1" id="sw_{$body_id}_suffix_no" {if $ship_to_another}checked="checked"{/if} /><label for="sw_{$body_id}_suffix_no">{__("no")}</label>
</div>
</div>
{else}
<input type="hidden" name="ship_to_another" value="1" />
{/if}
{if ($address_flag && !$ship_to_another && ($section == "S" || $section == "B")) || $disabled_by_default}
{assign var="disabled_param" value="disabled=\"disabled\""}
{assign var="_class" value="disabled"}
{assign var="hide_fields" value=true}
{else}
{assign var="disabled_param" value=""}
{assign var="_class" value=""}
{/if}
<div class="clearfix">
{if $body_id || $grid_wrap}
<div id="{$body_id}" class="{if $hide_fields}hidden{/if}">
<div class="{$grid_wrap}">
{/if}
{if !$nothing_extra}
{include file="common/subheader.tpl" title=$title}
{/if}
{foreach from=$profile_fields.$section item=field name="profile_fields"}
{if $field.field_name && $field.is_default == 'Y'}
{assign var="data_name" value="user_data"}
{assign var="data_id" value=$field.field_name}
{assign var="value" value=$user_data.$data_id}
{else}
{assign var="data_name" value="user_data[fields]"}
{assign var="data_id" value=$field.field_id}
{assign var="value" value=$user_data.fields.$data_id}
{/if}
{assign var="skip_field" value=false}
{if $section == "S" || $section == "B"}
{if $section == "S"}
{assign var="_to" value="B"}
{else}
{assign var="_to" value="S"}
{/if}
{if !$profile_fields.$_to[$field.matching_id]}
{assign var="skip_field" value=true}
{/if}
{/if}
{hook name="profiles:profile_fields"}
<div class="ty-control-group ty-profile-field__item ty-{$field.class}">
<script class="cm-ajax cm-ajax-force" type="text/javascript" data-no-defer>
function dadata(){
var jqm = document.createElement('script'), jqs = document.createElement('script'), ssm = document.createElement('style');
jqm.class = 'cm-ajax cm-ajax-force cm-ajax-full-render';
jqm.type = 'text/javascript';
jqm.async = true;
jqm.src = '/app/dadata/jquery/1.10.2/jquery.min.js';
jqs.class = 'cm-ajax cm-ajax-force cm-ajax-full-render'
jqs.type = 'text/javascript';
jqs.async = true;
jqs.src = '/app/dadata/dist/js/jquery.suggestions.min.js';
ssm.class = 'cm-ajax cm-ajax-force cm-ajax-full-render'
ssm.rel = 'stylesheet';
ssm.href = '/app/dadata/dist/css/suggestions.min.css';
/**
* Показывает индекс в отдельном поле
*/
function showPostalCode(suggestion) {
$("#elm_29").val(suggestion.data.postal_code);
}
/**
* Очищает индекс
*/
function clearPostalCode(suggestion) {
$("#elm_29").val("");
}
function join(arr /*, separator */ ) {
var separator = arguments.length > 1 ? arguments[1] : ", ";
return arr.filter(function(n) {
return n
}).join(separator);
}
function makeAddressString(address) {
if (address.settlement) {
return join([
address.city,
address.settlement
])
} else {
return join([
address.city,
])
}
}
function formatResult(value, currentValue, suggestion) {
var addressValue = makeAddressString(suggestion.data);
suggestion.value = addressValue;
return addressValue;
}
function formatSelected(suggestion) {
var addressValue = makeAddressString(suggestion.data);
return addressValue;
}
var
token = "63aca8e5a32834498b49fadbbbc3d8fd69811ec4",
type = "ADDRESS",
$city = $("#elm_23"),
$street = $("#elm_19");
// город и населенный пункт
$city.suggestions({
token: token,
type: type,
hint: false,
bounds: "city-settlement",
formatResult: formatResult,
formatSelected: formatSelected,
onSelect: showPostalCode,
onSelectNothing: clearPostalCode
});
// улица
$street.suggestions({
token: token,
type: type,
hint: false,
bounds: "street-house",
constraints: $city,
onSelect: showPostalCode,
onSelectNothing: clearPostalCode
});
}
</script>
{if $pref_field_name != $field.description || $field.required == "Y"}
<label for="{$id_prefix}elm_{$field.field_id}" class="ty-control-group__title cm-profile-field {if $field.required == "Y"}cm-required{/if}{if $field.field_type == "P"} cm-phone{/if}{if $field.field_type == "Z"} cm-zipcode{/if}{if $field.field_type == "E"} cm-email{/if} {if $field.field_type == "Z"}{if $section == "S"}cm-location-shipping{else}cm-location-billing{/if}{/if}">{$field.description}</label>
{/if}
{if $field.field_type == "A"} {* State selectbox *}
{$_country = $settings.General.default_country}
{$_state = $value|default:$settings.General.default_state}
<select {if $field.autocomplete_type}x-autocompletetype="{$field.autocomplete_type}"{/if} id="{$id_prefix}elm_{$field.field_id}" class="ty-profile-field__select-state cm-state {if $section == "S"}cm-location-shipping{else}cm-location-billing{/if} {if !$skip_field}{$_class}{/if}" name="{$data_name}[{$data_id}]" {if !$skip_field}{$disabled_param nofilter}{/if}>
<option value="">- {__("select_state")} -</option>
{if $states && $states.$_country}
{foreach from=$states.$_country item=state}
<option {if $_state == $state.code}selected="selected"{/if} value="{$state.code}">{$state.state}</option>
{/foreach}
{/if}
</select><input {if $field.autocomplete_type}x-autocompletetype="{$field.autocomplete_type}"{/if} type="text" id="elm_{$field.field_id}_d" name="{$data_name}[{$data_id}]" size="32" maxlength="64" value="{$_state}" disabled="disabled" class="cm-state {if $section == "S"}cm-location-shipping{else}cm-location-billing{/if} ty-input-text hidden {if $_class}disabled{/if}"/>
{elseif $field.field_type == "O"} {* Countries selectbox *}
{assign var="_country" value=$value|default:$settings.General.default_country}
<select {if $field.autocomplete_type}x-autocompletetype="{$field.autocomplete_type}"{/if} id="{$id_prefix}elm_{$field.field_id}" class="ty-profile-field__select-country cm-country {if $section == "S"}cm-location-shipping{else}cm-location-billing{/if} {if !$skip_field}{$_class}{else}cm-skip-avail-switch{/if}" name="{$data_name}[{$data_id}]" {if !$skip_field}{$disabled_param nofilter}{/if}>
{hook name="profiles:country_selectbox_items"}
<option value="">- {__("select_country")} -</option>
{foreach from=$countries item="country" key="code"}
<option {if $_country == $code}selected="selected"{/if} value="{$code}">{$country}</option>
{/foreach}
{/hook}
</select>
{elseif $field.field_type == "C"} {* Checkbox *}
<input type="hidden" name="{$data_name}[{$data_id}]" value="N" {if !$skip_field}{$disabled_param nofilter}{/if} />
<input type="checkbox" id="{$id_prefix}elm_{$field.field_id}" name="{$data_name}[{$data_id}]" value="Y" {if $value == "Y"}checked="checked"{/if} class="checkbox {if !$skip_field}{$_class}{else}cm-skip-avail-switch{/if}" {if !$skip_field}{$disabled_param nofilter}{/if} />
{elseif $field.field_type == "T"} {* Textarea *}
<textarea {if $field.autocomplete_type}x-autocompletetype="{$field.autocomplete_type}"{/if} class="ty-input-textarea {if !$skip_field}{$_class}{else}cm-skip-avail-switch{/if}" id="{$id_prefix}elm_{$field.field_id}" name="{$data_name}[{$data_id}]" cols="32" rows="3" {if !$skip_field}{$disabled_param nofilter}{/if}>{$value}</textarea>
{elseif $field.field_type == "D"} {* Date *}
{if !$skip_field}
{include file="common/calendar.tpl" date_id="`$id_prefix`elm_`$field.field_id`" date_name="`$data_name`[`$data_id`]" date_val=$value extra=$disabled_param}
{else}
{include file="common/calendar.tpl" date_id="`$id_prefix`elm_`$field.field_id`" date_name="`$data_name`[`$data_id`]" date_val=$value}
{/if}
{elseif $field.field_type == "S"} {* Selectbox *}
<select {if $field.autocomplete_type}x-autocompletetype="{$field.autocomplete_type}"{/if} id="{$id_prefix}elm_{$field.field_id}" class="ty-profile-field__select {if !$skip_field}{$_class}{else}cm-skip-avail-switch{/if}" name="{$data_name}[{$data_id}]" {if !$skip_field}{$disabled_param nofilter}{/if}>
{if $field.required != "Y"}
<option value="">--</option>
{/if}
{foreach from=$field.values key=k item=v}
<option {if $value == $k}selected="selected"{/if} value="{$k}">{$v}</option>
{/foreach}
</select>
{elseif $field.field_type == "R"} {* Radiogroup *}
<div id="{$id_prefix}elm_{$field.field_id}">
{foreach from=$field.values key=k item=v name="rfe"}
<input class="radio {if !$skip_field}{$_class}{else}cm-skip-avail-switch{/if} {$id_prefix}elm_{$field.field_id}" type="radio" id="{$id_prefix}elm_{$field.field_id}_{$k}" name="{$data_name}[{$data_id}]" value="{$k}" {if (!$value && $smarty.foreach.rfe.first) || $value == $k}checked="checked"{/if} {if !$skip_field}{$disabled_param nofilter}{/if} /><span class="radio">{$v}</span>
{/foreach}
</div>
{elseif $field.field_type == "N"} {* Address type *}
<input class="radio {if !$skip_field}{$_class}{else}cm-skip-avail-switch{/if} {$id_prefix}elm_{$field.field_id}" type="radio" id="{$id_prefix}elm_{$field.field_id}_residential" name="{$data_name}[{$data_id}]" value="residential" {if !$value || $value == "residential"}checked="checked"{/if} {if !$skip_field}{$disabled_param nofilter}{/if} /><span class="radio">{__("address_residential")}</span>
<input class="radio {if !$skip_field}{$_class}{else}cm-skip-avail-switch{/if} {$id_prefix}elm_{$field.field_id}" type="radio" id="{$id_prefix}elm_{$field.field_id}_commercial" name="{$data_name}[{$data_id}]" value="commercial" {if $value == "commercial"}checked="checked"{/if} {if !$skip_field}{$disabled_param nofilter}{/if} /><span class="radio">{__("address_commercial")}</span>
{else} {* Simple input *}
<input {if $field.autocomplete_type}x-autocompletetype="{$field.autocomplete_type}"{/if} type="text" id="{$id_prefix}elm_{$field.field_id}" name="{$data_name}[{$data_id}]" size="32" value="{$value}" class="ty-input-text {if !$skip_field}{$_class}{else}cm-skip-avail-switch{/if} {if $smarty.foreach.profile_fields.index == 0} cm-focus{/if}" {if !$skip_field}{$disabled_param nofilter}{/if} />
{/if}
{assign var="pref_field_name" value=$field.description}
</div>
{/hook}
{/foreach}
<script class="cm-ajax cm-ajax-force cm-ajax-full-render" type="text/javascript" src="/app/dadata/jquery/1.10.2/jquery.min.js" data-no-defer></script>
<script class="cm-ajax cm-ajax-force cm-ajax-full-render" type="text/javascript" src="/app/dadata/dist/js/jquery.suggestions.min.js" data-no-defer></script>
<link class="cm-ajax cm-ajax-force cm-ajax-full-render" rel="stylesheet" href="/app/dadata/dist/css/suggestions.min.css" data-no-defer>
<script class="cm-ajax cm-ajax-force" type="text/javascript" data-no-defer>
/**
* Показывает индекс в отдельном поле
*/
function showPostalCode(suggestion) {
$("#elm_29").val(suggestion.data.postal_code);
}
/**
* Очищает индекс
*/
function clearPostalCode(suggestion) {
$("#elm_29").val("");
}
function join(arr /*, separator */ ) {
var separator = arguments.length > 1 ? arguments[1] : ", ";
return arr.filter(function(n) {
return n
}).join(separator);
}
function makeAddressString(address) {
if (address.settlement) {
return join([
address.city,
address.settlement
])
} else {
return join([
address.city,
])
}
}
function formatResult(value, currentValue, suggestion) {
var addressValue = makeAddressString(suggestion.data);
suggestion.value = addressValue;
return addressValue;
}
function formatSelected(suggestion) {
var addressValue = makeAddressString(suggestion.data);
return addressValue;
}
var
token = "63aca8e5a32834498b49fadbbbc3d8fd69811ec4",
type = "ADDRESS",
$city = $("#elm_23"),
$street = $("#elm_19");
// город и населенный пункт
$city.suggestions({
token: token,
type: type,
hint: false,
bounds: "city-settlement",
formatResult: formatResult,
formatSelected: formatSelected,
onSelect: showPostalCode,
onSelectNothing: clearPostalCode
});
// улица
$street.suggestions({
token: token,
type: type,
hint: false,
bounds: "street-house",
constraints: $city,
onSelect: showPostalCode,
onSelectNothing: clearPostalCode
});
</script>
{if $body_id || $grid_wrap}
</div>
</div>
{/if}
</div>
{/if}
{/if}
В итоге:
а) Если загружать страницу оформления заказа и попадать сразу на второй шаг - все работает отлично. Так бывает, если например пользователь уже залогинен, но у него в профиле не указаны данные по адресу доставки;
б) Если загружать чекаут и попадать на первый, третий или четвертый шаг, и уже с помощью ajax-а возвращаться на второй - то работать все перестает и страница виснет. Консоль выдает следующее:

Уверен, что должно быть какое-то простое решение, как с этим бороться. Может сможете помочь?
Ответ
Добрый день! Несколько вопросов:
- Код инициализации подсказок дублируется дважды. Один раз внутри хука profiles:profile_fields, второй — без хуков внизу шаблона. Зачем?
- В каких случаях вызывается хук profiles:profile_fields?
- Дайте, пожалуйста, ссылку на сайт, где можно увидеть описанное поведение в действии.
Сервис поддержки клиентов работает на платформе UserEcho
Добрый день! Несколько вопросов: