Jump to content

Paramètre champs en fonction d'un autre dans admin controller module


Recommended Posts

Bonjour,

Voilà, j'ai un module avec un formulaire en admin permettant de choisir un client via un input (recherche ajax et autocomplete).

Une fois le client sélectionné je souhaite avoir un champs juste après qui propose un dropdown avec ses références de commande.

Comment puis-je faire pour conditionner la liste déroulante sur le choix de l'input précédent ? Sachant que je récupère l'id du customer dans un attribut name une fois qu'il est choisi.

Je vous remercie.

Capture d’écran 2022-04-26 à 11.58.25.png

Share this post


Link to post
Share on other sites

Bonjour Eolia,

Merci pour votre retour. Auriez-vous des détails à me donner sur la requête ajax à effectuer svp pour récupérer les commandes avec l'id_customer ?

En vous remerciant

Share this post


Link to post
Share on other sites

votre requete ajax appelle un fichier php (getOrders.php par exemple) et celui-ci appelle la fonction Order::getCustomerOrders($id_customer);

$id_customer que vous avez récupéré et envoyé en ajax

Share this post


Link to post
Share on other sites

D’accord je comprends le principe.

je dois transmettre ma variable à mon ModuleAdminController.

comment je peux faire pour la récupérer quand je suis dans ce controller ?

dois passer par une méthode ?

Share this post


Link to post
Share on other sites

D’accord c’est ce que j’ai commencé à faire.

dans la requête Ajax en jquery faut-il mettre des paramètres spécifiques ?

Share this post


Link to post
Share on other sites

J'ai fait ceci :

$('#customer_autocomplete_input').on('focusout', function(){
        if($('#inputCustomer').attr('value')){
            let id_customer_selected = $('#inputCustomer').attr('value');
            
            $.ajax({
                type: 'POST',
                dataType: 'json',
                url: ???, // Url vers l'admin controller
                cache: false,
                data: {
                    ajax: 1,
                    controller: 'AdminModule',
                    action: 'getcustomerid',
                    'id_customer_selected' : id_customer_selected,
                    token: '{$token}'
                },
                success: function (data) {
                    var data = jQuery.parseJSON(data);
                    id_customer_selected = data.id_customer_selected;
                    console.log(id_customer_selected);
                },
                error: function() {
                    console.log('Erreur lors de l\'envoi ajax');
                }
            })
            console.log(id_customer_selected);
        }
    });

Le seul soucis c'est que je ne sais pas comment récupérer dynamiquement l'url vers l'admin controller.

Avez-vous une suggestion svp ?

Merci

Share this post


Link to post
Share on other sites

Depuis le php de votre module qui appelle ce js, affectez la variable Smarty au tpl concerné

$ajax_link = $this->getModuleLink('NomDeVotreModule', 'NomDeVotreController', array(), Configuration::get('PS_SSL_ENABLED'));
$this->smarty->assign('ajax_link', $ajax_link);

et dans le tpl vous assignez cette variable Smarty en variable JS accessible depuis votre script

{addJsDef ajax_link=$ajax_link|escape:'quotes':'UTF-8'}

La variable JS ajax_link est à présent dispo dans votre script

Share this post


Link to post
Share on other sites

Posted (edited)

Ok je comprends, cependant le tpl en question c'est le renderForm() de mon adminController.

Est-ce que je peux utiliser ceci ? Et où dois-je le mettre dans mon adminController svp ? :

 

// Create a link with the path

$ajax_link = $this->context->link->getAdminLink('AdminController');

//define js value to use in ajax url

Media::addJsDef(array(

"ajax_link" => $ajax_link

));

 

Edited by GBPro (see edit history)

Share this post


Link to post
Share on other sites

public function setMedia() {
		
    Parent::setMedia();
    $this->context->controller->addJsDef(
           array(
                'ajax_link' => $this->context->link->getAdminLink('AdminNkmCustomerFile')
           )
    );	
}

 

Share this post


Link to post
Share on other sites

D'accord.

Bon maintenant le soucis c'est quand regardant ce qu'il envoie (data), je constate qu'il envoi toute une page html ... Et quand je spécifie dataType: 'json' l'envoi échoue.

$.ajax({
                method: 'POST',
                url: ajax_link,
                cache: false,
                contentType: "application/json",
                processData: false,
                data: id_customer_selected,
                success: function (data) {
                    console.log('Envoi réussi : ' + data);
                },
                error: function() {
                    console.log('Erreur lors de l\'envoi ajax');
                }
            })

Je ne comprends pas pourquoi data correspond à tout une page html et pas id_customer_selected.

 

Share this post


Link to post
Share on other sites

data: 'id_customer='+id_customer_selected,
dataType: 'json',

il faut nommer le paramètre ("id_customer") et  utiliser dataType et non ContentType

processData ne sert à rien.

Share this post


Link to post
Share on other sites

ça ne fonctionne pas...

quand je fais : 

$.ajax({
                method: 'POST',
                url: ajax_link,
                cache: 'false',
                dataType: 'json',
                data: 'id_customer='+id_customer_selected,
                success: function (data) {
                    console.log('Envoi réussi : ' + data);
                },
                error: function(data) {
                    console.log('Erreur lors de l\'envoi ajax : ' + data);
                }
            })

La requête ajax échoue et ça me retourne comme data : [object Object]

Share this post


Link to post
Share on other sites

Je commence un peu à être perdu.

Dans mon formulaire du adminController généré via renderForm je récupère bien l'id_customer en javascript quand je sélectionne le client.

Mais ensuite je n'arrive pas à envoyer cet id_customer de nouveau au adminController pour charger les options de la liste déroulante qui vient après, avec la liste de ses commandes.

Je n'arrive pas à faire la bonne requête ajax pour renvoyer l'id au controller et je ne sais pas comment récupérer cet id dans le controller.

Dois-je appeler une méthode au niveau des data de la requête ajax ?

Capture d’écran 2022-04-27 à 13.31.32.png

Share this post


Link to post
Share on other sites

Dans votre controller, ajoutez cette fonction:

	public function ajaxProcessLoadOrders()
	{
		$id_customer = (int)Tools::getValue('id_customer');
		// Votre fonction pour récupérer les commandes
		$orders = ....

		$this->context->smarty->assign(
			array(
				'orders' => $orders,
				'link' => $this->context->link
			)
		);

		die($this->module->display(_PS_MODULE_DIR_.$this->module->name.DIRECTORY_SEPARATOR.$this->module->name.'.php', 'order-list.tpl'));
	}

Elle va se déclencher lors de l'appel de votre js (auquel je rajoute l'action)

$.ajax({
	method: 'POST',
	url: ajax_link,
	cache: 'false',
	dataType: 'json',
	data: {
		ajax: true,
		action: 'loadorders',
		id_customer: id_customer_selected
	},
	success: function (data) {
		console.log('Envoi réussi : ' + data);
	},
	error: function(data) {
		console.log('Erreur lors de l\'envoi ajax : ' + data);
	}
})

Donc vous récupérez l'id_customer, vous l'envoyez à votre controleur en précisant l'action concernée (loadorders) et qu'on est en ajax.

Celui-ci va déclencher la fonction ajaxProcessLoadOrders() qui va récupérer les commandes, en extraire ce dont vous avez besoin (ID,Ref, etc...) et envoyer le tableau à un tpl (à créer dans /votremodule/views/templates/hook/order-list.tpl) qui va vous mettre le select en forme.

Le js va donc recevoir un js et il suffit de l'injecter à l'endroit voulu)

 

Dans le tpl vous avez juste à faire une boucle {foreach}

<select name="getRef">
{foreach $orders as $order}
  <option value="{$order.id}">{$order.reference}</option>
{/foreach}
</select>

 

Share this post


Link to post
Share on other sites

D'accord, mais dans mon cas je ne dois pas envoyer la variable à un tpl mais juste à mon adminController car je veux mettre les commandes dans un select :

array(
                    'type'    => 'select',
                    'label'   => $this->l('Order reference'),
                    'name'    => 'customer_orders',
                    'required' => true,
                    'options'  => array(
                        'query' => $options,
                        'id'    => 'id_order',
                        'name'  => 'name'
                    )
                ),

Est-ce que je dois aussi utiliser une fonction ajaxProcessLoadOrders ? Si oui est-ce que ajaxProcessLoadOrders doit retourner une valeur pour que je puisse l'utiliser en l'appellant et faire :

array(
                    'type'    => 'select',
                    'label'   => $this->l('Order reference'),
                    'name'    => 'customer_orders',
                    'required' => true,
                    'options'  => array(
                        'query' => $this->ajaxProcessLoadOrders(), // Récupération des commandes dans la fonction
                        'id'    => 'id_order',
                        'name'  => 'name'
                    )
                ),

 

Share this post


Link to post
Share on other sites

Non car le code que vous me montrez est un bout de helperform donc il faut le construire, faire un fetchTemplate et le renvoyer avec un die();

Les 2 solutions sont possibles.

Le helperform de base de votre controleur renvoie un contenu smarty à l'adminModule de Presta, dans votre cas vous voulez récupérer ce contenu pour l'injecter en js, ce n'est pas la même chose.

Je vous ai donné presque tout le code, pourquoi chercher plus compliqué ?

Share this post


Link to post
Share on other sites

Parce que je ne comprends pas comment on peut modifier un template généré par le renderForm(). J'avoue ne pas comprendre...

Share this post


Link to post
Share on other sites

ça c'est la partie qui m'intéresse dans mon renderForm() :

array(
                    'type' => 'customer_autocomplete',
                    'label' => $this->l('Customer'),
                    'name' => 'id_customer',
                    'lang' => false,
                    'col' => 5,
                ),
                array(
                    'type'    => 'select',
                    'label'   => $this->l('Order reference'),
                    'name'    => 'customer_orders',
                    'required' => true,
                    'options'  => array(
                        'query' => $options,
                        'id'    => 'id_order',
                        'name'  => 'name'
                    )
                )

$options doit contenir les commandes du client dynamiquement en fonction du champs customer_autocomplete du dessus (en se servant de la variable id_customer récupérée)

Share this post


Link to post
Share on other sites

il y a 8 minutes, GBPro a dit :

Parce que je ne comprends pas comment on peut modifier un template généré par le renderForm(). J'avoue ne pas comprendre...

En js, on injecte le contenu renvoyé par le controleur dans la page.

Comme Prestashop le fait pour les produits par exemple:

product.gif

Share this post


Link to post
Share on other sites

Ok donc il ne faut pas intégrer le champs select dans le renderForm() mais l'injection après en js ?

mais le template du formulaire admin du module rendu par renderForm() se situe où pour injecter ceci :

<select name="getRef">
{foreach $orders as $order}
  <option value="{$order.id}">{$order.reference}</option>
{/foreach}
</select>

 

Share this post


Link to post
Share on other sites

Il y a 17 heures, Eolia a dit :

envoyer le tableau à un tpl (à créer dans /votremodule/views/templates/hook/order-list.tpl)

Relisez mon post svp

Share this post


Link to post
Share on other sites

Ok je comprends mieux.

Par contre comment injecter ce tpl créé, juste après le champs de sélection du customer ? Faut-il l'appeler dans le tableau fields_form de l'admin controller ?

Comment lui dire précisément où aller ?

Share this post


Link to post
Share on other sites

Non, c'est votre js qui le fait au retour de l'ajax (seul le js peut modifier le DOM)

$.ajax({
	method: 'POST',
	url: ajax_link,
	cache: 'false',
	dataType: 'html',
	data: {
		ajax: true,
		action: 'loadorders',
		id_customer: id_customer_selected
	},
	success: function (data) {
		console.log(data);
		if(data){
			$(this).parent().append(data);
		}
	},
	error: function(data) {
		console.log('Erreur lors de l\'envoi ajax : ' + data);
	}
})

J'ai passé le retour en dataType html pour que ce soit plus simple pour vous

$(this) correspond à l'élément cliqué

Share this post


Link to post
Share on other sites

D'accord très bien. Merci

Donc si je veux par exemple modifier la valeur par défaut d'un autre input text en fonction de la référence de commande qui est sélectionnée parmi celles récupérées dans le select qui vient d'être injecté en js, je dois aussi le faire en js avec appel ajax c'est ça ?

Share this post


Link to post
Share on other sites

D'accord je comprends mieux, merci !

Et petite question quelle est la méthode pour rafraichir une front page dans une méthode ajax dans un frontController avec le die svp ?

Share this post


Link to post
Share on other sites

Ca dépend.

Si on veut "rafraichir" il faut regénérer le template et le renvoyer. Ce que fait Prestashop pour la page panier par exemple lorsque l'on modifie un des éléments du panier.

Soit on écrase tout, soit on met à jour que les éléments qui nous intéressent (grâce à leur ID)

Share this post


Link to post
Share on other sites

D'accord.

Dans le cas où on veut rafraichir la page car changement en BDD, il faut juste faire un setTemplate à la fin de la méthode ajax ?

Share this post


Link to post
Share on other sites

il faut faire un die() ensuite pour le revoyer au js.

Regardez comment est fait l'OrderOpcController par exemple:

                        case 'cartReload':
                            $this->_assignSummaryInformations();
                            if ($this->context->customer->id) {
                                $this->context->smarty->assign('address_list', $this->context->customer->getAddresses($this->context->language->id));
                            } else {
                                $this->context->smarty->assign('address_list', array());
                            }
                            $this->context->smarty->assign('opc', true);
                            $this->setTemplate(_PS_THEME_DIR_.'shopping-cart.tpl');
                            $this->display();
                            $this->ajaxDie();
                            break;

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

Cookies ensure the smooth running of our services. Using these, you accept the use of cookies. Learn More