In a user's Edit Info form, how do I include the name of the field(s) and user's input value(s) in a response from the model - ajax

On a Yii2 project, in a user's Edit Info form (inside a modal):
I'm currently figuring out which fields were changed using the jQuery .change() method, and I'm grabbing their value with jQuery's .val() method.
However, I want to do less with JavaScript and do more with Yii's framework.
I can see in the Yii debugger (after clicking into the AJAX POST request) that Yii is smart enough to know which fields were changed -- it's showing SQL queries that only UPDATE the fields that were changed.
What do I need to change in the controller of this action to have Yii include the name of the field changed -- including it's value -- in the AJAX response? (since my goal is to update the main view with the new values)
public function actionUpdateStudentInfo($id)
{
$model = \app\models\StudentSupportStudentInfo::findOne($id);
if ($model === null) {
throw new NotFoundHttpException('The requested page does not exist.');
}
$model->scenario = true ? "update-email" : "update-studentid";
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->renderAjax('_student_support_alert_success');
}
return $this->renderAjax("_edit_student_info",[
"model" => $model,
]);
}
I'm currently returning a static success view.

You can use $model->dirtyAttributes just after load the data to get a $attrib => $value pair array.
http://www.yiiframework.com/doc-2.0/yii-db-baseactiverecord.html#getDirtyAttributes()-detail (this docs says:)
Returns the attribute values that have been modified since they are loaded or saved most recently.
The comparison of new and old values is made for identical values using ===.
public array getDirtyAttributes ( $names = null )
(sorry for formatting, sent by mobile)

Related

Storing a new post tag if it doesn't exist in the table?

I have a single input field (using select2 plugin) in a blog post form which allow user to insert post tags from existing tags in the table or create new ones and store them in the Tag table and also attach them to the post when they hit submit post button. I've managed to get this work by filtering the input with array_filter(), if the input is !is_numeric the input will first get stored in Tag table and then attach the id to the post.
The problem with this is that it's not working when the new tag from the input is in full numeric type, like 2017 tag. Is there a solution to get this working so the new tag is not limited to string only but also numeric type ? and if possible, I don't want to use any package for this.
The post store method :
public function store(PostsReq $request) {
$input = $request->all();
$post = Post::create($input);
//Handle the tags
$getTags = $request->input('tagspivot');
$oldTags = array_filter($getTags, 'is_numeric');
$newTags = array_filter($getTags, function($item) {
return !is_numeric($item);
});
foreach ($newTags as $newTag) {
if ($tag = Tag::create(['title' => strtolower(trim($newTag))])) {
$oldTags[] = $tag->id;
}
}
$post->tags()->attach($oldTags);
// Upload Image
if ($request->hasFile('image')) {
$input['image'] = $this->uploadImage($request, $post);
}
return redirect()->route('postindex')->with($this->postStoreSuccess);
}
Here is three lines of code would be more than enough:
$tag = Tag::firstOrCreate([
'title' => $request->input('tagspivot'),
]);
You don't need to check for !is_numeric. However, in your form don't use tag id as value. use the title.

How to serialize ZF2 form object to JSON?

I'm using zf2 form object on the server and ajax code on the client to implement my registration form.
I post the form values in the ajax request, no problem, and the form gets them fine with
$form->setData($request->getPost());
After I validate the form and perform the registration on the server, I want to send the form back to the client, especially if there are errors, so I can show them to the user.
I'm looking for a standard way using zend or any plugin to serialise the form object into JSON format, so I can send it in the response to the AJAX call.
Any idea?
Well what you can do is run the validation on your form and after that you will return your form within a new JsonModel.
Here is a little example of how to handle your controller:
class RegistrationController extends AbstractActionController
{
public function RegisterAction()
{
$form = new RegisterForm();
$form->setInputFilter(new RegisterInputFilter());
if ($this->getRequest()->isPost()) {
$form->setData($this->getRequest()->getPost());
if($form->isValid()) {
// Handle your registration as the form is valid!
// return to some path after registration is complete.
// Show user he registered succesfully, etc. ;)
}
// Checks if the request is from JavaScript
if($this->getRequest()->isXmlHttpRequest()) {
return new JsonModel(array('registerForm' => $form));
}
}
return new ViewModel(array('registerForm' => $form));
}
}
Notice that the form object is holding all the invalid inputs including its message after validation.
I would take another approach just to completely render the ViewModel again so you can display the validation message much easier. On the side you could add Client Side (Javascript) validation as it's much more user-friendly, but that is just some fancy shizzle I would do ;) In case of rendering the ViewModel:
use Zend\View\Renderer\PhpRenderer;
if($this->getRequest()->isXmlHttpRequest()) {
$renderer = new PhpRenderer;
$registerViewModel = new ViewMOdel();
$registerViewModel->setTemplate('view/register.phtml');
return new JsonModel(array('registerViewModel' => $renderer->render($registerViewModel));
}
Note that not setting a template to your viewModel will result in ZF2 getting the default of the action (view/moduleName/registration/register.phtml) you are in! So in your case you don't need to use PhpRenderrer::setTemplate(). But I just hand it to you so you can change it if you are using any other file.
So now you will receive Json from our controller, in your javascript. Retrieve the new ViewModel from Json and remove the old ViewModel and replace it with the new. By removing the old, you also remove any Javascript that is bound to any element within the viewModel, so you might set the events on your body within your javascript or have it on your attributes in Form/RegistrationForm.
Hope this pushes you in the right direction.

How to use form_validation library rules for AJAX requests

One of my forms uses AJAX to send data. Since my page never reloads because of AJAX, is there a way I can still make use of form_validation to validate and output which fields are wrong? The url my form sends to using jquery is contact/ajax_send.
The entire AJAX works fine except I haven't inserted any validation yet.
Since you are using ajax to send the data, what you can do is, simply add the form_validation code calls before inserting into the database.
If there are any validation errors, you can either return the error messages as json response to the front end to display the error messages.
The form validation library assigns all errors that occurred to a private array called _error_array, but does not expose it or provide documentation on it (notice the first underscore?). Just return a json encoded object of the errors in the controller:
echo json_encode($this->form_validation->_error_array);
If you wish, you can extend CodeIgniter's form validation library, perhaps returning FALSE instead of an empty array... or whatever you see fit:
/* libraries/MY_Form_validation.php */
<?php
class MY_Form_validation extends CI_Form_validation
{
function __construct($config = array())
{
parent::__construct($config);
}
function error_array()
{
if (count($this->_error_array) === 0) return FALSE;
else return $this->_error_array;
}
}
Now, drop the initial underscore in the controller:
echo json_encode($this->form_validation->error_array);
Then decode and display errors on the client.
I found a method, thanks in part to Jordan's answer. This returns an array containing the names of the fields which have errors.
// library/MY_Form_validation.php
class MY_Form_validation extends CI_Form_validation {
public function get_field_data(){
return count($this->_field_data) ? $this->_field_data : FALSE;
}
}
// Controller file
$field_data = $this->form_validation->get_field_data();
foreach($field_data as $key=>$val){
if($key == '__proto__') break;
foreach($val as $k=>$v){
if($k == 'error' && !empty($v)) $errors[] = $key;
}
}
$return = array('success'=>FALSE, 'errors'=>$errors);
The above code checks the error key whether it's empty or not. Empty values mean that it passed the CI validation while none empty values would contain the string you see when you use validation_errors(). Since I'm after those fields which have errors, I only needed to see which values are not empty disregardig those which are.

Doctrine 2/ Multi-step form / entity into session

I am working under Symfony2 and Doctrine 2.1.6 and I try to setup a multi-step form.
Between each form page, I try to send the doctrine entity into $_SESSION.
According to that dotrine documentation it is possible and even the way to settle multipage forms:
http://docs.doctrine-project.org/en/2.1/cookbook/entities-in-session.html
But according to a lot of other post on stackoverflow, it is just not possible to send entities into session.
I have the following controller Action where i pretty much copied/ past the doctrine documentation.
public function indexAction(Request $request, $id)
{
$session = $request->getSession();
$em = $this->getDoctrine()->getEntityManager();
if (isset($_SESSION['propertyAdd'])) {
$property = $_SESSION['propertyAdd'];
$property = $em->merge($property);
}
else {
$property = new property;
}
$form = $this->createForm(new propertyType($this->getDoctrine()),$property);
// check form
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()){
$em->detach($property);
$_SESSION['propertyAdd'] = $property;
// redirection to next step here
}
}
return $this->render('AddProperty:'.$id.'.html.twig', array(
'form' => $form->createView(),));
}
the line $_SESSION['propertyAdd'] = $property; give me the following error:
Fatal error: Uncaught exception 'ErrorException' with message 'Notice: Unknown: "id" returned as member variable from __sleep() but does not exist in Unknown line 0' in G:..\Symfony\vendor\symfony\src\Symfony\Component\HttpKernel\Debug\ErrorHandler.php on line 65
If I replace this line by using the Symfony2 helper
$session->set('propertyAdd', $property);
It throws the following exception:
Symfony\Bundle\FrameworkBundle\DataCollector\RequestDataCollector::serialize() must return a string or NULL
Is the doctrine example workable.
This doesn't answer your question, but why would you:
Create an entity
Serialize it
Put it in the session (I personally don't believe it's a good thing to transform an object to a string)
Get it from the session in the form's next step
Deserialize it
Add the new data to it
Serialize it
Put it again in the session
An so on...
Why don't you store the form data directly in the session, and create the entity after all the form's steps were complete?
If you're doing this to validate the entity, you can simply use forms (that aren't linked to an entity) and add the validation constraints to them.

Codeigniter form validation failing when it should succeed

I'm building an admin utility for adding a bulk of images to an app I'm working on. I also need to to log certain properties that are associated with the images and then store it all into the database.
So basically the script looks into a folder, compares the contents of the folder to records in the database. All of the info must be entered in order for the database record to be complete, hence the form validation.
The validation is working, when there are no values entered it prompts the entry of the missing fields. However it happens even when the fields ARE filled.
I'm doing something a bit funny which may be the reason.
Because I'm adding a bulk of images I'm creating the data within a for loop and adding the validation rules within the same for loop.
Here is the results:
http://s75151.gridserver.com/CI_staging/index.php/admin_panel/bulk_emo_update
Right now I have default test values in the form while testing validation. The submit button is way at the bottom. I'm printing POST variable for testing purposes.
Here is the code:
function bulk_emo_update() {
$img_folder_location = 'img/moodtracker/emos/';//set an image path
$emo_files = $this->mood_model->get_emo_images('*.{png,jpg,jpeg,gif}', $img_folder_location); //grab files from folder
$emo_records = $this->mood_model->get_all_emos(); //grab records from db
$i=1; //sets a counter to be referenced in the form
$temp_emo_info = array(); //temp vairable for holding emo data that will be sent to the form
//loop through all the files in the designated folder
foreach($emo_files as $file) {
$file_path = $img_folder_location.$file;//builds the path out of the flder location and the file name
//loops through all the database reocrds for the pupose of checking to see if the image file is preasent in the record
foreach($emo_records as $record) {
//compairs file paths, if they are the
if($record->picture_url != $file_path) {
//FORM VALIDATION STUFF:
$rules['segment_radio['.$i.']'] = "required";
$rules['emo_name_text_feild['.$i.']'] = "required";
//populating the temp array which will be used to construct the form
$temp_emo_info[$i]['path'] = $file_path;
$temp_emo_info[$i]['name'] = $file;
}
}
$i++;
}
//sets the reference to validation rules
$this->validation->set_rules($rules);
//checks to see if the form has all it's required fields
if ($this->validation->run() == FALSE) { //if validation fails:
print_r($_POST);
//prepairs the data array to pass into the view to build the form
$data['title'] = 'Bulk Emo Update';
$data['intro_text'] = 'fill out all fields below. hit submit when finished';
$data['emos_info'] = $temp_emo_info;
$this->load->view('admin_bulk_emo_update_view',$data);
} else { // if it succeeds:
//printing for test purposes
print_r($_POST);
$this->load->view('form_result');
}
}
I'm new to codeigniter and php in general so if anything looks outrageously weird please tell me, don't worry about my feelings I've got thick skin.
if ($this->validation->run() == FALSE)
if you are calling the run() method of the validation class every time the script is run, will it ever return TRUE and run the else? Maybe a different return?
I'm a little cornfused by what's going on. Generally, if I'm having a problem like this, I will figure out a way to force the result I'm looking for. e.g. in your code, I'd force that else to run... once I get it to run, break down what happened to make it run. Rudimentary, but it has served me well.
You use array of rules in
$this->form_validation->set_rules()
wrong.
If you want to pass the rules in array you must stick to the key names like described here http://codeigniter.com/user_guide/libraries/form_validation.html#validationrulesasarray
So instead of
$rules['input_name'] = "required"
try this:
array(
'field' => 'input_name',
'label' => 'Name that you output in error message',
'rules' => 'required'
)

Resources