Creating a View, defining on Click callback elsewhere and passing a parameter


#1

Hi there,

what I am trying to achieve:
I want to create a view which displays several records. For each record, a delete button will be added. I would like to use it as follows:

First: in another file, create the view and define a function which is passed to each delete button, something like:

$email_address_container = new \Pmg\View\EmailAddressWithDeleteView();
$email_address_container->onClickCallback = function($r) use ($modal_email, $email_address_container) {     
    $modal_email->removeRecipient($r);
    ....
};

Second: In the view itself, I would need to pass the current record:

	foreach($this->model as $recipient) {
		...
		$buttonDelete = $v->add(new \atk4\ui\Label(['', 'pmg-mtomdelete', 'icon'=>'remove circle']));
		if(is_callable($this->onClickCallback)) {
			$buttonDelete->on('click', $this->onClickCallback);
		}
	}

And this is where I am stuck, passing the current record (in this case $recipient) to ->on(‘click’, $this->onClickCallback)…
The logic of onClickCallback would be pretty simple: Remove the current record from $modal_email recipient list, update the View $email_address_container via JS… But: for this I need to pass the current record :slight_smile:
Possible or is the way I am trying to do it not possible?

Best Regards
Philipp


#2

Just to clarify the requirements.

  1. You are using custom HTML
  2. Some part of your template repeats for all records.
  3. You want to be able to interact with any record.
  4. You want to define a PHP callback.

This seems to be a good chance to use Lister, as for the interactivity, I can provide an example.


#3

Hi,

I think my basic aprroach was bad, it could have lead to many event listeners attached to the same object. In general no problem, but not good code IMHO.

So I moved to a different solution:

  1. Attach the event handler to the container where the single list items are in
  2. use the second parameter of View->on() to delegate the event listener to sub-elements of the container
  3. use the fourth parameter of View->on() to pass additional parameters to the callback in PHP.

So its about lists like this:
listwithdelete

I wanted to have some functionality on the delete buttons, and after deleting something I want to only update the lists’ HTML to display the change.

So now, the code in PHP looks like this:

$email_address_container = $f->layout->add(['View'], 'Recipients');
$email_addresses = new \Pmg\View\MultipleRecordsWithDeleteView('EmailRecipientView');
$email_address_container->add($email_addresses);
$email_addresses->model = $outbox_email->recipients;
$email_address_container->on('click',
    '.pmg-mtomdelete',
    function($e, $data_id, $data_class) use($outbox_email, $email_addresses) {
        ... 
        Callback code. $data_id and $data_class are parameters passed by JS to the callback and defined below as 'args' =>. 
        They are used to identify the record to be deleted. Of course its within the HTML code of each record as data-class="something" and data-id="some-id".
        
        To reload the list, the following code is used:
        return $email_addresses->js()->replaceWith($email_addresses->getHTML());
    },
    ['args' => [
        (new \atk4\ui\jQuery(new \atk4\ui\jsExpression('this')))->siblings('.eoo-data-item')->data('id'),
        (new \atk4\ui\jQuery(new \atk4\ui\jsExpression('this')))->siblings('.eoo-data-item')->data('class'),
    ]]);

So now the list itself does not contain any event listener and I do not have to worry about them when refreshing the view via JS.


#4

Of course when doing something like this, security can be an issue, as it takes parameters from the client side which could be faked.