模块上的产品自动完成输入 (Prestashop)
Product autocomplete input on module (Prestashop)
我正在开发一个必须列出现有产品列表的 prestashop 模块。
对于模块的配置面板,使用 renderForm() 和 getContent(),我正在尝试复制 "accesories" 功能,您开始在输入中写入产品的一些信息,它会显示匹配的产品。选择该产品时,它会添加到列表中。像这样:
这是目录/产品/关联选项卡的屏幕截图。
我正在尝试 PS 1.6.0.14 和 PS1.6.1.0RC3。我如何复制此功能以获取模块配置面板上的产品列表?
我试着查看这里 Prestashop AdminProductsController.php,但我真的不明白一半信息的来源。
我认为要实现该功能,renderForm() 函数是不够的,因为您必须绑定一些 javascript 和一些自定义 html.
编写一个功能齐全的模块的过程有点长,但是以附件功能为起点就不会那么难,而且您总是可以参考 "how-to-do-it"。
我会这样做:
1) 首先创建您的
getContent()
能够显示自定义模板和与您的模块关联的产品的功能,因此我们会有一些东西:
public function getContent(){
//post process part to save the associations
if(Tools::isSubmit('saveMyAssociations'){
... //we will see it later
}
$my_associations = MyModule::getAssociationsLight($this->context->language->id,Tools::getValue('id_product')); //function that will retrieve the array of all the product associated on my module table.
$this->context->smarty->assign(array(
'my_associations' => $my_associations,
'product_id' => (int)Tools::getValue('id_product')
));
return $this->display(__FILE__, 'views/templates/admin/admintemplate.tpl'); //custome template to create the autocomplete
}
//our little function to get the already saved list, for each product we will retrieve id, name and reference with a join on the product/product_lang tables.
public static function getAssociationsLight($id_lang, $id_product, Context $context = null)
{
if (!$context)
$context = Context::getContext();
$sql = 'SELECT p.`id_product`, p.`reference`, pl.`name`
FROM `'._DB_PREFIX_.'my_associations`
LEFT JOIN `'._DB_PREFIX_.'product` p ON (p.`id_product`= `id_product_2`)
'.Shop::addSqlAssociation('product', 'p').'
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (
p.`id_product` = pl.`id_product`
AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').'
)
WHERE `id_product_1` = '.(int)$id_product;
return Db::getInstance()->executeS($sql);
}
2) 创建一个能够显示自动完成和列表的模板。
在这里,我们将循环遍历保存的关联以创建我们的自动完成列表,我们将使用一些隐藏字段来跟踪 ids/name 以及一个可见列表,我们将为每一行设置一个删除按钮。
<input type="hidden" name="inputMyAssociations" id="inputMyAssociations" value="{foreach from=$my_associations item=accessory}{$accessory.id_product}-{/foreach}" />
<input type="hidden" name="nameMyAssociations" id="nameMyAssociations" value="{foreach from=$my_associations item=accessory}{$accessory.name|escape:'html':'UTF-8'}¤{/foreach}" />
<div id="ajax_choose_product_association">
<div class="input-group">
<input type="text" id="product_autocomplete_input_association" name="product_autocomplete_input_association" />
<span class="input-group-addon"><i class="icon-search"></i></span>
</div>
</div>
<div id="divMyAssociations">
{foreach from=$my_associations item=accessory}
<div class="form-control-static">
<button type="button" class="btn btn-default delAssociation" name="{$accessory.id_product}">
<i class="icon-remove text-danger"></i>
</button>
{$accessory.name|escape:'html':'UTF-8'}{if !empty($accessory.reference)}{$accessory.reference}{/if}
</div>
{/foreach}
</div>
<input type="submit" name="submitMyAssociations" id="submitMyAssociations" value="Send"/>
<input type="hidden" name="productId" id="productId" value="{$product_id|escape:'html'}"/>
3) 现在我们可以添加 javascript 以在主输入上绑定自动完成并为每个操作执行所有逻辑
$(document).ready(function(){
//our function wrapper.
var initMyAssociationsAutocomplete = function (){
//initialize the autocomplete that will point to the default ajax_products_list page (it returns the products by id+name)
$('#product_autocomplete_input_association')
.autocomplete('ajax_products_list.php', {
minChars: 1,
autoFill: true,
max:20,
matchContains: true,
mustMatch:true,
scroll:false,
cacheLength:0,
formatItem: function(item) {
return item[1]+' - '+item[0];
}
}).result(addAssociation);
//as an option we will add a function to exclude a product if it's already in the list
$('#product_autocomplete_input_association').setOptions({
extraParams: {
excludeIds : getAssociationsIds()
}
});
};
//function to exclude a product if it exists in the list
var getAssociationsIds = function()
{
if ($('#inputMyAssociations').val() === undefined)
return '';
return $('#inputMyAssociations').val().replace(/\-/g,',');
}
//function to add a new association, adds it in the hidden input and also as a visible div, with a button to delete the association any time.
var addAssociation = function(event, data, formatted)
{
if (data == null)
return false;
var productId = data[1];
var productName = data[0];
var $divAccessories = $('#divCrossSellers');
var $inputAccessories = $('#inputMyAssociations');
var $nameAccessories = $('#nameMyAssociations');
/* delete product from select + add product line to the div, input_name, input_ids elements */
$divAccessories.html($divAccessories.html() + '<div class="form-control-static"><button type="button" class="delAssociation btn btn-default" name="' + productId + '"><i class="icon-remove text-danger"></i></button> '+ productName +'</div>');
$nameAccessories.val($nameAccessories.val() + productName + '¤');
$inputAccessories.val($inputAccessories.val() + productId + '-');
$('#product_autocomplete_input_association').val('');
$('#product_autocomplete_input_association').setOptions({
extraParams: {excludeIds : getAssociationsIds()}
});
};
//the function to delete an associations, delete it from both the hidden inputs and the visible div list.
var delAssociations = function(id)
{
var div = getE('divMyAssociations');
var input = getE('inputMyAssociations');
var name = getE('nameMyAssociations');
// Cut hidden fields in array
var inputCut = input.value.split('-');
var nameCut = name.value.split('¤');
if (inputCut.length != nameCut.length)
return alert('Bad size');
// Reset all hidden fields
input.value = '';
name.value = '';
div.innerHTML = '';
for (i in inputCut)
{
// If empty, error, next
if (!inputCut[i] || !nameCut[i])
continue ;
// Add to hidden fields no selected products OR add to select field selected product
if (inputCut[i] != id)
{
input.value += inputCut[i] + '-';
name.value += nameCut[i] + '¤';
div.innerHTML += '<div class="form-control-static"><button type="button" class="delAssociation btn btn-default" name="' + inputCut[i] +'"><i class="icon-remove text-danger"></i></button> ' + nameCut[i] + '</div>';
}
else
$('#selectAssociation').append('<option selected="selected" value="' + inputCut[i] + '-' + nameCut[i] + '">' + inputCut[i] + ' - ' + nameCut[i] + '</option>');
}
$('#product_autocomplete_input_association').setOptions({
extraParams: {excludeIds : getAssociationsIds()}
});
};
//finally initialize the function we have written above and create all the binds.
initMyAssociationsAutocomplete();
//live delegation of the deletion button to our delete function, this will allow us to delete also any element added after the dom creation with the ajax autocomplete.
$('#divMyAssociations').delegate('.delAssociation', 'click', function(){
delAssociations($(this).attr('name'));
});
});
4) 现在您只需要保存由模块自动完成建立的关联,我建议首先删除对给定产品建立的任何关联,然后保存所有关联。所以你不必关心插入或更新条目
public function getContent(){
//post process part
if(Tools::isSubmit('saveMyAssociations'){
$product_id = (int)Tools::getValue('productId');
// see the function below, a simple query to delete all the associations on a product
$this->deleteMyAssociations($product_id);
if ($associations = Tools::getValue('inputMyAssociations'))
{
$associations_id = array_unique(explode('-', $associations));
if (count($associations_id))
{
array_pop($associations_id);
//insert all the association we have made.
$this->changeMyAssociations($associations_id, $product_id);
}
}
}
}
protected function deleteMyAssociations($product_id){
return Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'my_associations` WHERE `id_product_1` = '.(int)$product_id);
}
protected function changeMyAssociations($associations_id, $product_id){
foreach ($associations_id as $id_product_2)
Db::getInstance()->insert('my_associations', array(
'id_product_1' => (int)$product_id,
'id_product_2' => (int)$id_product_2
));
}
希望它能帮助你度过这一切。
prestashop 中有一个自动完成插件,您必须为此使用它。它在 js->jquery->plugins 中,你必须将这个插件添加到你的模块中才能使其工作。
我正在开发一个必须列出现有产品列表的 prestashop 模块。
对于模块的配置面板,使用 renderForm() 和 getContent(),我正在尝试复制 "accesories" 功能,您开始在输入中写入产品的一些信息,它会显示匹配的产品。选择该产品时,它会添加到列表中。像这样:
这是目录/产品/关联选项卡的屏幕截图。
我正在尝试 PS 1.6.0.14 和 PS1.6.1.0RC3。我如何复制此功能以获取模块配置面板上的产品列表?
我试着查看这里 Prestashop AdminProductsController.php,但我真的不明白一半信息的来源。
我认为要实现该功能,renderForm() 函数是不够的,因为您必须绑定一些 javascript 和一些自定义 html.
编写一个功能齐全的模块的过程有点长,但是以附件功能为起点就不会那么难,而且您总是可以参考 "how-to-do-it"。 我会这样做:
1) 首先创建您的
getContent()
能够显示自定义模板和与您的模块关联的产品的功能,因此我们会有一些东西:
public function getContent(){
//post process part to save the associations
if(Tools::isSubmit('saveMyAssociations'){
... //we will see it later
}
$my_associations = MyModule::getAssociationsLight($this->context->language->id,Tools::getValue('id_product')); //function that will retrieve the array of all the product associated on my module table.
$this->context->smarty->assign(array(
'my_associations' => $my_associations,
'product_id' => (int)Tools::getValue('id_product')
));
return $this->display(__FILE__, 'views/templates/admin/admintemplate.tpl'); //custome template to create the autocomplete
}
//our little function to get the already saved list, for each product we will retrieve id, name and reference with a join on the product/product_lang tables.
public static function getAssociationsLight($id_lang, $id_product, Context $context = null)
{
if (!$context)
$context = Context::getContext();
$sql = 'SELECT p.`id_product`, p.`reference`, pl.`name`
FROM `'._DB_PREFIX_.'my_associations`
LEFT JOIN `'._DB_PREFIX_.'product` p ON (p.`id_product`= `id_product_2`)
'.Shop::addSqlAssociation('product', 'p').'
LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (
p.`id_product` = pl.`id_product`
AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').'
)
WHERE `id_product_1` = '.(int)$id_product;
return Db::getInstance()->executeS($sql);
}
2) 创建一个能够显示自动完成和列表的模板。 在这里,我们将循环遍历保存的关联以创建我们的自动完成列表,我们将使用一些隐藏字段来跟踪 ids/name 以及一个可见列表,我们将为每一行设置一个删除按钮。
<input type="hidden" name="inputMyAssociations" id="inputMyAssociations" value="{foreach from=$my_associations item=accessory}{$accessory.id_product}-{/foreach}" />
<input type="hidden" name="nameMyAssociations" id="nameMyAssociations" value="{foreach from=$my_associations item=accessory}{$accessory.name|escape:'html':'UTF-8'}¤{/foreach}" />
<div id="ajax_choose_product_association">
<div class="input-group">
<input type="text" id="product_autocomplete_input_association" name="product_autocomplete_input_association" />
<span class="input-group-addon"><i class="icon-search"></i></span>
</div>
</div>
<div id="divMyAssociations">
{foreach from=$my_associations item=accessory}
<div class="form-control-static">
<button type="button" class="btn btn-default delAssociation" name="{$accessory.id_product}">
<i class="icon-remove text-danger"></i>
</button>
{$accessory.name|escape:'html':'UTF-8'}{if !empty($accessory.reference)}{$accessory.reference}{/if}
</div>
{/foreach}
</div>
<input type="submit" name="submitMyAssociations" id="submitMyAssociations" value="Send"/>
<input type="hidden" name="productId" id="productId" value="{$product_id|escape:'html'}"/>
3) 现在我们可以添加 javascript 以在主输入上绑定自动完成并为每个操作执行所有逻辑
$(document).ready(function(){
//our function wrapper.
var initMyAssociationsAutocomplete = function (){
//initialize the autocomplete that will point to the default ajax_products_list page (it returns the products by id+name)
$('#product_autocomplete_input_association')
.autocomplete('ajax_products_list.php', {
minChars: 1,
autoFill: true,
max:20,
matchContains: true,
mustMatch:true,
scroll:false,
cacheLength:0,
formatItem: function(item) {
return item[1]+' - '+item[0];
}
}).result(addAssociation);
//as an option we will add a function to exclude a product if it's already in the list
$('#product_autocomplete_input_association').setOptions({
extraParams: {
excludeIds : getAssociationsIds()
}
});
};
//function to exclude a product if it exists in the list
var getAssociationsIds = function()
{
if ($('#inputMyAssociations').val() === undefined)
return '';
return $('#inputMyAssociations').val().replace(/\-/g,',');
}
//function to add a new association, adds it in the hidden input and also as a visible div, with a button to delete the association any time.
var addAssociation = function(event, data, formatted)
{
if (data == null)
return false;
var productId = data[1];
var productName = data[0];
var $divAccessories = $('#divCrossSellers');
var $inputAccessories = $('#inputMyAssociations');
var $nameAccessories = $('#nameMyAssociations');
/* delete product from select + add product line to the div, input_name, input_ids elements */
$divAccessories.html($divAccessories.html() + '<div class="form-control-static"><button type="button" class="delAssociation btn btn-default" name="' + productId + '"><i class="icon-remove text-danger"></i></button> '+ productName +'</div>');
$nameAccessories.val($nameAccessories.val() + productName + '¤');
$inputAccessories.val($inputAccessories.val() + productId + '-');
$('#product_autocomplete_input_association').val('');
$('#product_autocomplete_input_association').setOptions({
extraParams: {excludeIds : getAssociationsIds()}
});
};
//the function to delete an associations, delete it from both the hidden inputs and the visible div list.
var delAssociations = function(id)
{
var div = getE('divMyAssociations');
var input = getE('inputMyAssociations');
var name = getE('nameMyAssociations');
// Cut hidden fields in array
var inputCut = input.value.split('-');
var nameCut = name.value.split('¤');
if (inputCut.length != nameCut.length)
return alert('Bad size');
// Reset all hidden fields
input.value = '';
name.value = '';
div.innerHTML = '';
for (i in inputCut)
{
// If empty, error, next
if (!inputCut[i] || !nameCut[i])
continue ;
// Add to hidden fields no selected products OR add to select field selected product
if (inputCut[i] != id)
{
input.value += inputCut[i] + '-';
name.value += nameCut[i] + '¤';
div.innerHTML += '<div class="form-control-static"><button type="button" class="delAssociation btn btn-default" name="' + inputCut[i] +'"><i class="icon-remove text-danger"></i></button> ' + nameCut[i] + '</div>';
}
else
$('#selectAssociation').append('<option selected="selected" value="' + inputCut[i] + '-' + nameCut[i] + '">' + inputCut[i] + ' - ' + nameCut[i] + '</option>');
}
$('#product_autocomplete_input_association').setOptions({
extraParams: {excludeIds : getAssociationsIds()}
});
};
//finally initialize the function we have written above and create all the binds.
initMyAssociationsAutocomplete();
//live delegation of the deletion button to our delete function, this will allow us to delete also any element added after the dom creation with the ajax autocomplete.
$('#divMyAssociations').delegate('.delAssociation', 'click', function(){
delAssociations($(this).attr('name'));
});
});
4) 现在您只需要保存由模块自动完成建立的关联,我建议首先删除对给定产品建立的任何关联,然后保存所有关联。所以你不必关心插入或更新条目
public function getContent(){
//post process part
if(Tools::isSubmit('saveMyAssociations'){
$product_id = (int)Tools::getValue('productId');
// see the function below, a simple query to delete all the associations on a product
$this->deleteMyAssociations($product_id);
if ($associations = Tools::getValue('inputMyAssociations'))
{
$associations_id = array_unique(explode('-', $associations));
if (count($associations_id))
{
array_pop($associations_id);
//insert all the association we have made.
$this->changeMyAssociations($associations_id, $product_id);
}
}
}
}
protected function deleteMyAssociations($product_id){
return Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'my_associations` WHERE `id_product_1` = '.(int)$product_id);
}
protected function changeMyAssociations($associations_id, $product_id){
foreach ($associations_id as $id_product_2)
Db::getInstance()->insert('my_associations', array(
'id_product_1' => (int)$product_id,
'id_product_2' => (int)$id_product_2
));
}
希望它能帮助你度过这一切。
prestashop 中有一个自动完成插件,您必须为此使用它。它在 js->jquery->plugins 中,你必须将这个插件添加到你的模块中才能使其工作。