Cake PHP event chaining with Js Helper - cakephp

Hello you coders out there,
I want to do an event chaining with the Js helper but can´t figure out how to do that with the cookbook.
Scenario:
I have an input field, which is fired onkeyup with ajax. That works fine.
The goal:
The ajax call should be fired after putting 3 digits into the field, not everytime.
My thoughts:
Maybe the chaining of the helper could get me out. I thought the return true would tell the helper to go on, otherwise do nothing. But I didn´t find any info. My code so far:
<?php $check = "
if($(this).val().length >3){
return true;
};"; ?>
<?php echo $this->Js->get('#ajaxSearchSCourier')->event('keyup', $check)->request(
array('controller'=>'Posts', 'action'=>'index'),
array(
'update' => '#erfolgreich_ajax',
'before' => $before,
'success' => $success,
'async' => true,
'dataExpression' => true,
'method' => 'post',
'data'=>$this->Js->serializeForm(array('isForm'=>'false', 'inline'=>'true'))
)
);
?>
I hope you have an idea. Many thanks in advance,
Karl

Forget the JsHelper and write js code yourself. Check my related answer here.

Related

How to build a Url with multiple query (?) params with CakePHP 3

I'm working in a redirection for autocomplete some fields, and I'm doing this with simple javascript.
I wanted to print a URL without A tag, then I used Url builder. I've seen documentation and reviewed source code for this method in Router class but I see something that I can't understand.
All works right when I use Url builder with this code:
<?= $this->Url->build(['controller' => 'places', 'action' => 'add', '?' => ['event_id' => $event->id]]) ?>
Url genetared is:
/places/add?event_id=1
But, when I add more params in ? query, I get a & in url, but I didn't find in docs something for elimitate special chars filter.
<?= $this->Url->build(['controller' => 'places', 'action' => 'add', '?' => ['from' => 'events','id' => $event->id]])
// Generates: /places/add?from=events&id=1
// I want: /places/add?from=events&id=1
?>
Is there an option to get & without &? If I put all in one string, I get UTF codes %5D and those. I'm using url in a javascript window.open, then I'm not printing in html body.
I see line 597 in http://api.cakephp.org/3.0/source-class-Cake.Routing.Router.html#509-646, but I don't understand if $url = static::_applyUrlFilters($url); code is changing something.
Thank you!
The URL helper is ment to be used for generating URLs for use in markup contexts, therefore they are being entity encoded using the h() function.
In case you need the plain URLs, don't use the URL helper, but the Router::url() method instead.
use Cake\Routing\Router;
Router::url([
'controller' => 'places',
'action' => 'add',
'?' => [
'from' => 'events',
'id' => $event->id
]
]);

Paginator prev not working with Ajax View

I'm having this issue where the previous button of the paginator is disabled (have disabled class) by default, even if I am in to second or third or any page. If I remove the 'id => prevPage' and 'id => nextPage' then it works fine but I have to use it to make another ajax request.
I'm using this in my ajax view..
echo $this->Paginator->prev('< ' . __('Zur'), array('id' => 'prevPage'), null, array('class' => 'prev disabled'));
echo $this->Paginator->next(__('Vor') . ' >', array('id' => 'nextPage'), null, array('class' => 'next disabled'));
while in my controller, I have;
if($this->RequestHandler->isAjax()) {
$this->autoRender = false;
$this->set('products',$this->paginate('Product'));
$this->set('page',$page);
$this->render('ajaxView');
}
I did a little googling which suggested me it might be bug.. is it? How do I solve?
I wasn't able to find the error, but I fixed the error by going through other way. I was using 'offset' while I was paginating in the controller before which had introduced the error, but using the other way around by requesting to '.../page:3?q=' on the ajax call, did solved the problem. Thanks to #hereshem for the quick fix.

Deleting Multiple selected items from table

In my table I have a column with a check box for each row. I want to be able to delete all the selected items. I found the code from this website and modified it for my own stuff.
Link
I followed the website's naming convention for the check boxes and it is as follows:
<td> <?php echo $this->Form->checkbox('LocalClocks.id.['.$LocalClock['LocalClock']['id'].']', array('value' => $LocalClock['LocalClock']['id'])); ?></td>
This is the code in my controller for the deleteSelected() function:
public function deleteSelected()
{
foreach($this->data['LocalClocks'] as $key => $value)
{
if($value != 0)
{
$this->LocalClock->del($value);
}
}
$this->redirect($this->referer());
}
This is the code for the actual delete button (just in case it is needed):
<?php echo $this->Form->postLink('Delete Selected', array('action' => 'deleteSelected'), array('confirm' => 'Are you sure?')); ?>
There are a couple things I think might be the problem:
The code was written for an older version of cake, I think the website said 1.3, but I don't know what to update/correct in the existing code to make it work.
The delete button is the same as the one on cakephp's website on the blog tutorial. The only change I made was removing the id of the item to delete, because im not deleting a single item but multiple items.
Any help would be great.
Your checkbox input should be something like this
echo $this->Form->checkbox('LocalClocks.'.$LocalClock['LocalClock']['id'], array(
'value' => $LocalClock['LocalClock']['id'],
'hiddenField' => false
));
This will create a data array that will look like this
array(
'LocalClocks' => array(
1 => 1,
42 => 1
)
);
And will omit any unchecked ones from the data array because we're not using the hidden field. Finally, just a couple changes to your action
public function deleteSelected()
{
foreach($this->request->data['LocalClocks'] as $key => $value)
{
$this->LocalClock->delete($key);
}
$this->redirect($this->referer());
}
I prefer using Model::delete() to Model::deleteAll() because it runs the callbacks, where deleteAll does not.
Finally, your link will actually be a submit button. This will POST the data to the controller.
echo $this->Form->end('Submit');
If you want to use ajax, use the JsHelper to submit it instead. The following creates an Ajax submission that updates the dom element #mytable with the results of the action (in this case the referer that you redirect to).
echo $this->Js->submit('Submit', array(
'update' => '#mytable'
));
echo $this->Form->end();
once you got the list of your checked boxes; rather than using foreach loop to delete your ids one by one try this:
$this->Model->deleteAll(array('Model.column' => array($keys)));

Validation problems with multiple checkboxes (HABTM) on CakePHP form

Short version
I have some HABTM checkboxes on a form. Validation is working correctly (at least one checkbox needs to be checked for validation to pass) but the CakePHP error message divs aren't being generated as they should be.
Long Version
I have a from which allows users to fill in their name and email address and then choose from a list of brochures (checkboxes) they'd like to receive.
The form looks like this:
<?php
echo $this->Form->create('Request',array('action' => 'index'));
echo $this->Form->input('id');
echo $this->Form->input('name');
echo $this->Form->input('email');
echo $this->Form->input('Brochure',array(
'label' => __('Information Required:',true),
'type' => 'select',
'multiple' => 'checkbox',
'options' => $list,
'selected' => $this->Html->value('Brochure.Brochure'),
));
echo $this->Form->submit('Submit');
echo $this->Form->end();
?>
In my controller, $list is set as like this:
$this->Request->Brochure->find('list',array('fields'=>array('id','name')));
After reading the 2nd answer (posted by user448164) in HABTM form validation in CakePHP on Stack Overflow, I set my Request model up like this:
<?php
class Request extends AppModel {
var $name = 'Request';
function beforeValidate() {
foreach($this->hasAndBelongsToMany as $k=>$v) {
if(isset($this->data[$k][$k]))
{
$this->data[$this->alias][$k] = $this->data[$k][$k];
}
}
}
var $validate = array(
'name' => array(
'rule' => 'notEmpty',
'message' => 'Please enter your full name'
),
'email' => array(
'rule' => 'email',
'message' => 'Please enter a valid email address'
),
'Brochure' => array(
'rule' => array('multiple', array('min' => 1)),
'message' => 'Please select 1'
),
);
?>
This actually works 99% well. If none of the checkboxes are checked, validation fails as it should do. However, the only problem is that Cake isn't setting the "error" class on the <div>, nor is it creating the <div class="error-message">Please select 1</div> as it should.
For name and email, there is no problem - the error divs are being created properly.
So, to clarify, validation is working for my HABTM checkboxes. The only problem is that the error divs aren't being generated.
I'm posting this here as this is actually a much better question than the related question you found.
I was banging my head against a wall trying to handle the same problem of getting the validation error to show up in the page. I'm using CakePHP v1.2 and I hit a similar problem although I have actually split out the HABTM into the individual tables i.e. Request->BrochuesRequest->Brochure. This is because I can't have it deleting and re-adding the joining table rows at will.
Firstly I think the accepted answer from your linked question assumes that you are doing a save / saveAll when the beforeValidate call is triggered, however I was doing it through a validates call. The difference is that you need to call the Request->set method first. It was an article by Jonathan Snook on Multiple Validation Sets pointed me to that issue.
The second issue is actually getting the error message to appear was down to the $field value you use when calling invalidate. For ages I was including the model as well as the field assuming that this was how it matched the invalidate call to the input, i.e. you have $form->input('BrochuresRequest.brochures_id') so you need $this->BrochuresRequest->invalidate('BrochuresRequest.brochures_id').
However that is wrong you just want $this->BrochuresRequest->invalidate('brochures_id').
<?php
// requests/add view
echo $form->input('BrochuresRequest.brochures_id', array('multiple' => true));
// requests_controller
function add() {
if (!empty($this->data)) {
$this->Request->create();
// critical set to have $this->data
// for beforeValidate when calling validates
$this->Request->set($this->data);
if ($this->Request->validates()) {
$this->Request->saveAll($this->data);
}
}
}
// request model
function beforeValidate() {
if (count($this->data['BrochuresRequest']['brochures_id']) < 1) {
$this->invalidate('non_existent_field'); // fake validation error on Project
// must be brochures_id and not BrochuresRequest.brochures_id
$this->BrochuresRequest->invalidate('brochures_id', 'Please select 1');
return false;
}
return true;
}
?>
A few of the other things that I picked up on the way through:
You don't need a separate $form->error in the view
I couldn't for the life of me get the 'multiple' validation rule to work in the model
The accepted answer checks for an isset but I believe that this isn't required and masked the problem of there being no $this->data being passed through.
The beforeValidate should return false if you want it to prevent any save action.

Using HtmlHelper on Model to insert links in returned errors

I'm working with CakePHP and trying to understand the best ways to make my application consistent and logical.
Now I'm trying to working with Model data validation and handling validation errors in the view, I have a doubt on how should I do if I like to insert some link inside the returned error, for example for a forgotten password.
Is it good to use (if it's possibile) HtmlHelper inside the Model to return consistent links inside my application, or should I think about another way?
<?php
App::import('Helper', 'Html');
class User extends AppModel {
var $name = 'User';
var $validate = array (
'email' => array (
'checkEmail' => array (
'rule' => array('email', true),
'message' => 'Email not valid message.'
),
'checkUnique' => array (
'rule' => 'isUnique',
'message' => 'This email is allready in the db, if you forgot the password, '.(string)$this->Html->link('click here', array('controller' => 'users', 'action' => 'password-recover')).'.'
)
)
// the rest of the code...
This doesn't work because it seems I can't chain the message string with HTML string.
Does exist e smartest way to do that, or should I simply insert the html string without the HtmlHelper?
If you really want HTML in your validation messages CakePHP provides a way to do this, no breaking Cake, no writing a lot of code.
In your $validation just use whatever HTML you would like to have presented to the user.
In your view when you create your FormHelper::input($fieldName, array $options) pass the following array to $options:
$options = array('error' => array(
'attributes' => array('escape' => false)
))
See this page to learn more about the $options['error'] ...options.
Alternatively, if you want all inputs with no HTML escaping you can pass $options['inputDefaults'] when you create the form.
this is a difficult topic because
you might need to break MVC
validation is as in your case usually in $validate and cannot contain dynamic stuff
for 1)
you can also use Router::url() with manual HTML
you can use BBcode or pseudo-markup and translate this into real links in the view/element of the flashmessage
for 2)
use __construct() and $this->validate to use dynamic elements if needed
In PHP, properties of a class (such as $validate) have to be initialized with constant values.
<?php
class User extends AppModel {
public $validate = array(
'email' => array(
'checkUnique' => array(
'rule' => array('isUnique'),
'message' => 'This email address has already been claimed, possibly by you. If this is your email address, use the reset password facility to regain access to your account'
),
),
);
public function beforeValidate($options = array()) {
$this->validate['email']['checkUnique']['message'] = String::insert(
$this->validate['email']['checkUnique']['message'],
array('link' => Router::url(array('action' => 'password-recover')))
);
return true;
}
You are making it hard on yourself. The helpers are not accessible in the model and controller. And for good reason: the M and C shouldn't be concerned with the V.
There are ways to do exactly as you want (but involves considerably more code). Since you ask for the smartest way: What's wrong with just echo the reset password link in the view, after the login form? Just echo 'Forgot your password? '.$this->Html->link('Click here', array('controller' => 'users', 'action' => 'password-recover'));
I don't agree on breaking the MVC logic. I also tried all the array('escape' => false) possible ways (in Form->input, in Form->error and even in the model) and none of them worked with me! (cakephp 2.0)
"Anh Pham" answer is the easiest and simplest way. In addition to that, I returned empty error message from model validation ('errorMessage' => false ; doesn't work in cakePhp 2.0).
Because I wanted to pass a variable to the view to build the link there (MVC), in the controller I check if the field is invalidated:
$invlaidFields = array_keys($this->Model->validationErrors();
if ( in_array('myField', $invalidFields) ){
...
}
In the view, I check if the field was invalidated, I then echo my error message giving it class error-message so it looks the same as the rest error messages.
if ($this->Form->('myFields')) { ... echo '<span class="error-message">error message'. $this->Html->link(...).'</span>'; }
Hope it helps somebody out there.
P.S. It's always a good practice to mention what cakePHP version you are using...
To cakephp2 you can use the following:
//model validation
'company' => array('notempty' => array('rule' => array('notempty'),'message' => "select one company o send email to contact",),)
//front
<?php if ($this->Form->isFieldError('Register.company')): ?>
<span class="text-danger"><?php echo $this->Form->error('Register.company', null, array('escape'=>false)); ?></span>
<?php endif; ?>

Resources