Skip to content
J-C HERON edited this page Apr 4, 2021 · 12 revisions

Ajax

Ajax integration

An instance of jQuery (phpMv-ui with semantic) is injected by default in the controllers (defined in config.php)

"di"=>[
	"@exec"=>array("jquery"=>function ($controller){
				return \Ubiquity\core\Framework::diSemantic($controller);
			})
],

The $jquery property must be added in the javadoc of a controller to activate the code completion of your IDE on this injection:

 /**
  * @property JsUtils $jquery
  */
class MyController extends ControllerBase{}

Script generation in a view

The view is displayed on the jquery instance, with the renderView method. This allows the compilation of the scripts, and their passage to the view.

	#[Route('_default',name:'home')]
	public function index(){
		$this->jquery->renderView("MyController/index.html");
	}

They are then integrated via the script_foot variable (the Twig raw filter removes the HtmlEntities protection and makes this script executable).

MyController/index.html

{{ script_foot | raw }}

Ajax Get sample

The getHref method transforms the click on a tags with a data-target attribute into requests performed via ajax. The listenerOn attribute allows all future links in the body of the page to be transformed.

The data-target attribute defines the target of ajax requests. It defines the zone of the page in which the response will be displayed.

public function initialize() {
	parent::initialize();
	$this->jquery->getHref('a[data-target]','',['listenerOn'=>'body']);
}

MyController/index.html

<h1 class="ui inverted header">{{ title }}</h1>
<a class="ui inverted button" href="{{ path('ajax') }}" data-target="#ajax-content">Lien vers ajax</a>
<div class="ui text container" id="ajax-content">

</div>
{{ script_foot|raw }}

image

Action requested by the ajax link in example:

#[Route('ajax',name:'ajax')]
public function ajax(){
	$datas=['message'=>'This is an ajax message'];
	$this->loadDefaultView($datas);
}

The associated view: MyController/ajax.html

<div class="ui icon inverted message">
    <i class="ui circle info icon"></i>
    {{ message }}
</div>

image

Ajax and the page refresh issue

If the user refreshes the page, Ajax is no longer requested, and only the Ajax part of the page will be refreshed and displayed. This problem needs to be solved, so that the navigation with or without Ajax leads to the same result. The solution is to modify the display of the Ajax action: If Ajax is not requested, we call the previous action, which provided the context of the page, and we ask it to display the content of the Ajax action, returned in a string.

The solution

We add to the main view an outlet variable which will be able to display generated by the ajax action, requested without ajax.

MyController/index.html

<h1 class="ui inverted header">{{ title }}</h1>
<a class="ui inverted button" href="{{ path('ajax') }}" data-target="#ajax-content">Lien vers ajax</a>
<div class="ui text container" id="ajax-content">
{{ outlet | raw }}
</div>
{{ script_foot|raw }}

Modification of the Ajax action :

If Ajax is not requested, the main method is called, passing it the contents of the Ajax action in the outlet variable:

#[Route('ajax',name:'ajax')]
public function ajax(){
	$datas=['message'=>'This is an ajax message'];
	if(!URequest::isAjax()){
		$this->getView()->setVar('outlet',$this->loadDefaultView($datas,true));
		$this->index();
		return ;
	}
	$this->loadDefaultView($datas);
}

With or without Ajax, the result of the /ajax request is now always the same.

Ajax Post form sample

The postFormAction transform the submission of the form tags with a data-target attribute into requests performed via ajax. The listenerOn attribute allows all future form in the body of the page to be transformed.

The data-target attribute defines the target of ajax requests. It defines the zone of the page in which the response will be displayed. These forms must also set the action attribute.

public function initialize() {
	parent::initialize();
        if(! URequest::isAjax()){
	    $this->jquery->postFormAction('form[data-target]','',['listenerOn'=>'body']);
        }
}

A form sample

MyFormController/form.html

<form class="ui form" action='{{ path("main.submit") }}' method="post" id="frm" data-target="#response">
    <div class="ui input">
        <input name="firstname" id="firstname" type="text" placeholder="Enter your firstname">
    </div>
    <input class="ui button" type="submit" value="Validate">
</form>
<div id="response">Response</div>
{{ script_foot | raw }}

Loaded by an action in the controller:

	#[Route(path: "/form",name: "main.form")]
	public function form(){
		$this->jquery->renderView('MyFormController/form.html');
	}

The action for the form submiting:

	#[Route(path: "form/submit",name: "main.submit")]
	public function submit(){
		var_dump($_POST);
	}