I´ve been working with aspnet for quite a while, and i´d like to implement aspnet viewstate with in php (exactly in codeigniter). Is there a way to implement ASP ViewState with Codeigniter ?
This answer will accomplish some of the goals of Viewstate in that is will preserve control values between form submits. If you navigate away from the page the data will be lost. But it's the same for Viewstate. The example code make heavy use of the CodeIgniter (CI) Framework.
Here is some documentation related to the parts of CI used here.
Form Validation
Form Helper
Session
The CI_Form_validation library suffers from not being able to keep validation results across a redirect. This class extends CI_Form_validation to overcome that limitation.
File: application/libraries/My_Form_validation.php
/**
* Extends CI_Form_validation to facilitate using the Post/Redirect/Get pattern for form handling.
* https://en.wikipedia.org/wiki/Post/Redirect/Get
* http://solidlystated.com/design/best-way-to-process-forms-with-php/
*
* The base class (CI_Form_validation) has the protected property $_field_data
* which holds all the information provided by form_validation->set_rules()
* and all the results gathered by form_validation->run().
* Form Helper and Form_Validation use the $_field_data to re-populate fields and present error messages.
*
* To use this class you must have CodeIgniter Session setup and working.
*
* This class stores $_field_data in session flash data for use in the controller method that is the
* redirect target.
*
* Class is handy for defining custom validation methods which will NOT require the "callback_" prefix.
*
*/
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation
{
public function __construct($rules = array())
{
parent :: __construct($rules);
$this->CI->load->library('session');
}
/**
* Enhanced version of form_validation->run(). Sets a $_SESSION item with the contents of $this->_field_data
*
* #param string $group The name of the validation group to run
* #param bool $persistent If TRUE save the state of $_field_data even if validation passes
* #return boolean TRUE on success and FALSE on failure
*/
public function run($group = '', $persistent = FALSE)
{
if(parent:: run($group))
{
if($persistent)
{
$this->CI->session->set_flashdata('validation_field_data', $this->_field_data);
}
return TRUE;
}
$this->CI->session->set_flashdata('validation_field_data', $this->_field_data);
return FALSE;
}
/**
* This is used in the redirect target defined in the form processing controller/method
*
* #return bool TRUE if $_SESSION['validation_field_data'] is set. It indicates that validation failed.
* Returns FALSE if there is no indication that validation has failed or even been run.
*/
public function is_failed_validation()
{
if(isset($_SESSION['validation_field_data']))
{
// Validation failed or is being persisted.
$this->_field_data = $_SESSION['validation_field_data'];
return TRUE;
}
return FALSE;
}
/**
* A validation function to cleanup strings
*
* #param string $str Value of the field
* #return string|bool The sanitized string or FALSE if filter_var() fails
*/
public function sanitize_str($str)
{
return filter_var($str, FILTER_SANITIZE_STRING);
}
/**
* A do-nothing routine assigned to any field we want included in validation results
* #return boolean
*/
public function alwaysTrue($val)
{
return TRUE;
}
}
Hopefully the comments explain what's going on. One major thing to understand is that form_validation only captures the $_POST data for controls that have validation rules. That's the reason for the "do-nothing" validation routine alwaysTrue(). Use this rule on any control where you want the values to persist.
The following controller shows a usage example.
File: application/controllers/Viewstate.php
class Viewstate extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load
->library('form_validation', NULL, 'fv') //renames 'form_validation' to 'fv'
->helper(['form', 'url']);
$this->fv->set_error_delimiters('<span class="error">', '</span>');
}
public function index()
{
$this->fv->is_failed_validation(); //captures validation data if it's there
//Define some data for consumption by CI's Form Helper functions
$data['username_field'] = [
'name' => 'username',
'id' => 'username',
'value' => $this->fv->set_value('username'),
'class' => 'your_css',
];
$data['confirm_username_field'] = [
'name' => 'usernameconf',
'id' => 'usernameconf',
'value' => $this->fv->set_value('usernameconf'),
'class' => 'your_css',
];
$data['comment_field'] = [
'name' => 'comment',
'id' => 'comment',
'value' => $this->fv->set_value('comment'),
'class' => 'comment',
];
$data['project_lead_field'] = [
'name' => 'project_lead',
'value' => 1,
'checked' => $this->fv->set_radio('project_lead', 1, FALSE)
];
$selected_status = ['None' => "None"]; //default dropdown item
$status_items = ["None" => "None", "Good" => "Good", 'Bad' => 'Bad', "Ugly" => "Ugly"];
//recover previously posted select item - if any
if($item = $this->session->validation_field_data['status']['postdata'])
{
$selected_status = [$item => $item];
}
$data['status_field'] = [
'name' => 'status',
'options' => $status_items,
'selected' => $selected_status
];
$this->load->view('testcase_view', $data);
}
/**
* This is the "action" that processes the form's posted data
*/
public function process()
{
//set rules and error messages at same time
$this->fv
->set_rules('username', 'User Name', ['trim', 'required', 'matches[usernameconf]'],
['required' => '<em>{field}</em> required.', 'matches' => "User Names don't match."])
->set_rules('usernameconf', '', ['trim', 'required'], ['required' => 'Retyping the User Name is required.'])
->set_rules('comment', "", ['trim', 'sanitize_str'])
->set_rules('project_lead', "", 'alwaysTrue')
->set_rules('status', "", 'alwaysTrue')
;
//So an uncheck checkbox will be part of the $_POST array
if(!isset($_POST['project_lead']))
{
$_POST['project_lead'] = 0;
}
if(FALSE == $this->fv->run('', TRUE))
{
redirect('viewstate');
}
else
{
//do something with field values e.g.
//$this->model->instert($_POST);
redirect('viewstate'); //to prove the page state is persistent
}
}
}
I included some actual field validation so readers can see how that works and how the validation results persist across a redirect.
Here is the view
File: application/views/textcase_view.php
<!DOCTYPE html>
<html>
<head>
<title>Test Persistent Page</title>
<style type="text/css">
p{
margin: 0;
}
.error {
color: #FF0000;
font-size: small;
}
.fld-label{
color: #555;
font-size: .9em;
}
.comment{
color: Blue;
font-weight: bold;
}
div{
margin-bottom: 1em;
}
div + .fld-label
/*div + .error*/
{
margin-bottom: 0;
}
</style>
</head>
<body>
<?= form_open('viewstate/process'); ?>
<span class="fld-label">User Name</span>
<div><?= form_input($username_field) ?>
<p><?= form_error('username'); ?></p>
</div>
<div class="fld-label">Retype User Name</div>
<div><?= form_input($confirm_username_field) ?>
<p><?= form_error('usernameconf'); ?></p>
</div>
<div class="fld-label">Comment</div>
<div><?= form_input($comment_field); ?></div>
<div class="fld-label">Project Lead?</div>
<div><?= form_checkbox($project_lead_field); ?></div>
<div class="fld-label">Status</div>
<div><?= form_dropdown($status_field); ?></div>
<p><input type="submit" value="Submit"></p>
<?= form_close(); ?>
</body>
</html>
The view makes heavy use of Form Helper functions such as form_open, form_close, form_input, etc.
Related
What i need to achieve is when i select a category, then the Skills relating to that category is made available to choose from in the form. the relationship between category and skills is a manytomany rel. also i have followed this tutorial from here https://symfony.com/doc/current/form/dynamic_form_modification.html#form-events-submitted-data and have arrived at the following.
Form
class ProjectType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('category', EntityType::class, array(
'class'=>'AppBundle:Category',
'choice_label'=>'name'
))
->add('name', TextType::class, array('label' => 'Name','attr' => array('class'=>'form-control')));
$formModifier = function (FormInterface $form, Category $category = null) {
$skills = null === $category ? array() : $category->getSkill();
$skills = $this->getDoctrine()->getEntityManager()->merge($skills);
$form->add('skill', EntityType::class, array(
'class' => 'AppBundle:Skill',
'placeholder' => '',
'choices' => $skills,
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
// this would be your entity, i.e. project
$data = $event->getData();
$formModifier($event->getForm(), $data->getCategory());
}
);
$builder->get('category')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
// It's important here to fetch $event->getForm()->getData(), as
// $event->getData() will get you the client data (that is, the ID)
$category = $event->getForm()->getData();
// since we've added the listener to the child, we'll have to pass on
// the parent to the callback functions!
$formModifier($event->getForm()->getParent(), $category);
}
);
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
$event->stopPropagation();
}, 900);
Controller
$project = new Project();
$form = $this->createForm(ProjectType::class, $project)
->add('save', SubmitType::class, array(
'label' => 'Save',
'attr'=>array('class'=>'btn btn-md btn-info')
));
$form->handleRequest($request);
if ($form->isValid()) {
$project->setCreated(new \DateTime());
$project->setDiscontinue(0);
$project->setViewed(0);
$em = $this->getDoctrine()->getManager();
$em->persist($project);
$em->flush();
}
return $this->render('default/project.html.twig',array(
'form' => $form ->createView(),
));
View
{% block content%}
<div class="">
{{ form_start(form) }}
{{ form_row(form.category) }}
{{ form_row(form.skill) }}
{{ form_end(form) }}
</div>
{% endblock %}
script>
var $category = $('#project_category');
$category.change(function() {
// ... retrieve the corresponding form.
var $form = $(this).closest('form');
// Simulate form data, but only include the selected sport value.
var data = {};
data[$category.attr('name')] = $category.val();
// Submit data via AJAX to the form's action path.
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
// Replace current position field ...
$('#project_skill').replaceWith(
// ... with the returned one from the AJAX response.
$(html).find('#project_skill')
);
// Position field now displays the appropriate positions.
}
});
});
I Get this error
Entities passed to the choice field must be managed. Maybe persist them in the entity manager?
this is the relationship btw Category and Skill
/**
* #ORM\ManyToMany(targetEntity="Skill", inversedBy="category")
* #ORM\JoinTable(name="category_skills")
*/
private $skill;
public function __construct()
{
$this->skill = new ArrayCollection();
}
/**
* #ORM\ManyToMany(targetEntity="Category", mappedBy="skill")
*/
private $category;
public function __construct() {
$this->category = new ArrayCollection();
}
I hope this help some one out. first i give credit to #J.M. Echevarría i got this answer from here i could easily just have ask you to follow the link but that answer was 2014 so i would just update it for the sake of the newbies that might require the solution. now that that is of the way.
what i want to achieve is to let user select from a range of Categories (entity A) then have the second input Skill(entity B) based on entity A. to do that we will use 2 different select boxes: one for selecting your Category , and the next select box with all the skills for that category.
The form (projetType)
<?php
namespace AppBundle\Form\Type;
use AppBundle\Entity\Category;
//not that you have to import the entity manager to your form we will register this in our service later
use Doctrine\ORM\EntityManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* #author Akoh Ojochuma Victor <akoh.chuma#gmail.com>
*/
class ProjectType extends AbstractType
{
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, array(
'attr' => array('class'=>'form-control','placeholder'=>'Project name e.g Paint a house' ),
));
// other filds
// Add listeners
$builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData'));
$builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmit'));
}
protected function addElements(FormInterface $form, Category $category = null) {
// Add the category element
$form->add('category', EntityType::class, array(
'class'=>'AppBundle:Category',
'attr'=>array("id"=>"demoSelect","class"=>"form-control"),
'choice_label'=>'name',
'required' => false,
'expanded'=>false,
'data' => $category,
'placeholder' => 'Choose a category (optional)',
));
// For the sake of this project all the skills are presented to you if you
// did not choose any particular category
$skills = $this->em->getRepository('AppBundle:Skill')->findAll();
//this would happen when the user selects a category
if ($category) {
// Fetch the skills for the selected category
$repo = $this->em->getRepository('AppBundle:Skill');
// this is your custom query for retrieving the skills from the database
$skills = $repo->findCategorySkill($category, array('name' => 'asc'));
}
//add the skills
$form->add('skill', EntityType::class, array(
'class'=>'AppBundle:Skill',
//pass in the skills gotten as choice
'choices' => $skills,
'attr'=>array("class"=>"form-control"),
'choice_label'=>'name',
'placeholder' => 'What skills are required ?',
'multiple' => true,
'required' => true,
'expanded' => false,
'label' => false,
));
}
function onPreSubmit(FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
// Note that the data is not yet hydrated into the entity.
$category =$this->em->getRepository('AppBundle:Category')->find($data['category']);
$this->addElements($form, $category);
}
function onPreSetData(FormEvent $event) {
$project = $event->getData();
$form = $event->getForm();
// We might have an empty account (when we insert a new account, for instance)
$category = $project->getSkill() ? $project->getSkill()->getCategory() : null;
$this->addElements($form, $category);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Project',
));
}
/**
* #return string
*/
public function getName()
{
return 'app_project';
}
}
Ajax controller
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use AppBundle\Entity\Bid;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Ajax controller.
*
* #Route("/ajax")
*/
class AjaxController extends Controller
{
/**
* get skill for category with ajax when a user select a category
*
* #Route("/category/skills", name="get-category-new")
*/
public function ajaxAction(Request $request) {
if (! $request->isXmlHttpRequest()) {
throw new NotFoundHttpException();
}
// Get the province ID
$id = $request->query->get('category_id');
$result = array();
// Return a list of cities, based on the selected province
$repo = $this->getDoctrine()->getManager()->getRepository('AppBundle:Skill');
$skills = $repo->findCategorySkill($id);
foreach ($skills as $skill) {
$result[$skill->getName()] = $skill->getId();
}
return new JsonResponse($result);
}
}
Twig Template
{# ajax stuuf but if this conflict with any of your js feel free to remove or try diff version #}
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="http://code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#project_category').change(function(){
var val = $(this).val();
//alert('sucess');
$.ajax({
type: "POST",
url: "{{ url('get-category-new') }}?category_id=" + val,
success: function(data) {
// Remove current options
$('#project_skill').html('');
$.each(data, function(k, v) {
$('#project_skill').append('<option value="' + v + '">' + k + '</option>');
});
}
});
return false;
});
});
</script>
repository
<?php
namespace AppBundle\Repository;
use Doctrine\ORM\EntityRepository;
/**
* SkillRepository
*
* This class was generated by the Doctrine ORM. Add your own custom
* repository methods below.
*/
class SkillRepository extends EntityRepository
{
public function findCategorySkill($category)
{
return $this
->createQueryBuilder('l')
->select('p')
->from('AppBundle:Skill','p')
->join('p.category', 'c')
->where('c = :category')
->setParameter('category', $category)
->getQuery()
->getResult();
}
}
this is your query please note this is specific so feel free to put this to your tase.
service include this in your services
app.form_project:
class: AppBundle\Form\Type\ProjectType
arguments: ["#doctrine.orm.entity_manager"]
tags:
- { name: form.type, alias: app_project_creation }
yap thats all in case you need detailed explanation visit here here
I have two models in Yii2 (masterTransaction and splitTransaction), where each masterTransactions can have multiple splitTransactions. Each splitTransaction has an attribute 'amount'. My problem is I need to validate if the sum over all 'amount' attributes is 0.
My first solution was to make another model called Transaction, in which I had an attribute where I saved an instance of the masterTransaction model and another attribute with an array of splitTransaction instances. I did the validation with a custom inline validatior, which work perfectly.
Transaction model
class Transaction extends Model
{
public $masterTransaction;
public $splitTransactions;
public function init()
{
$this->masterTransaction = new MasterTransaction();
$this->splitTransactions[] = new SplitTransaction();
}
public function rules()
{
return [
['splitTransactions', 'validateSplitTransactions'],
];
}
public function validateSplitTransactions($attribute, $params)
{
$sum = 0;
foreach ($this->$attribute as $transaction) {
$sum = bcadd($sum, $transaction->amount, 3);
}
if ($sum != 0) {
$this->addError($attribute, 'The sum of the entries has to be 0');
}
}
public function save()
{
$this->masterTransaction->save();
foreach ($this->splitTransactions as $splitTransaction) {
$splitTransaction->master_transaction_id = $this->masterTransaction->id;
$splitTransaction->save();
}
}
}
Controller function to create the model
public function actionCreate()
{
$transaction = new Transaction();
$count = count(Yii::$app->request->post('SplitTransaction', []));
for ($i = 1; $i < $count; $i++) {
$transaction->splitTransactions[] = new SplitTransaction();
}
if ($transaction->masterTransaction->load(Yii::$app->request->post()) && Model::loadMultiple($transaction->splitTransactions, Yii::$app->request->post())) {
$transaction->masterTransaction->user_id = Yii::$app->user->id;
foreach ($transaction->splitTransactions as $splitTransaction) {
$splitTransaction->user_id = Yii::$app->user->id;
}
if ($transaction->validate()) {
$transaction->save();
}
}
return $this->render('create', [
'transaction' => $transaction,
]);
}
But when I tried building a form to input the data, I ran into a problem with the Ajax validation. The validation would work, but Yii didn't know where to put the error message, so it just deleted it.
I suspect that this is just not the preferred way in Yii2 model my data, but I don't really have another idea. Maybe someone has some ideas for me.
Option 1.
It depends on your view file codes. Does your form contains "splitTransactions" variable? If not, you can put it like this
<?= $form->field($model, 'splitTransactions')->hiddenInput(['maxlength' => true])->label(false); ?>
The variable will be hidden, but still show errors. In some case validation will not be fired because of empty value of "splitTransactions" variable.
"splitTransactions" should contain some value to fire validation. You can put some value to if before pasting the form like this
$model->splitTransactions=1;
Option 2.
You can add error to other variable (which form contains) like this
public function validateSplitTransactions($attribute, $params)
{
$sum = 0;
foreach ($this->$attribute as $transaction) {
$sum = bcadd($sum, $transaction->amount, 3);
}
if ($sum != 0) {
$this->addError('transaction_number', 'The sum of the entries has to be 0');
}
}
Look, form should contain "transaction_number" variable. Error will be added to "transaction_number" input.
Option 3. In my experience.
It is better to separate ajax validation from form action url a.g. create another controller action for ajax validation and use it.
Example
Create model FeedbackForm
class FeedbackForm extends Model
{
public $name;
public $email;
public $text;
/**
* #inheritdoc
*/
public function rules()
{
return [
[['name', 'email', 'text'], 'required'],
[['name', 'email'], 'string', 'max' => 128],
[['email'], 'email'],
[['text'], 'string', 'max' => 512],
];
}
public function attributeLabels()
{
return [
'name' => \Yii::t('front', 'Name'),
'email' => \Yii::t('front', 'Email'),
'text' => \Yii::t('front', 'Message text'),
];
}
}
put actions to SiteSontroller
public function actionFeedback()
{
$model= new \frontend\models\FeedbackForm;
$model->load(Yii::$app->request->post());
if($model->validate()) {
$newFeed=new \frontend\models\Feedback;
$newFeed->create_time=new \yii\db\Expression('NOW()');
$newFeed->name=$model->name;
$newFeed->email=$model->email;
$newFeed->is_new=1;
$newFeed->text=$model->text;
if($newFeed->save()) {
\Yii::$app->session->setFlash('success', \Yii::t('front', 'Your message has accepted'));
} else {
\Yii::$app->session->setFlash('error', \Yii::t('front', 'Error on save'));
}
} else {
\Yii::$app->session->setFlash('error', \Yii::t('front', 'Data error'));
}
return $this->redirect(['/site/index']);
}
public function actionFeedbackvalidate()
{
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$model= new \frontend\models\FeedbackForm;
$model->load(Yii::$app->request->post());
return ActiveForm::validate($model);
}
And create form inside view
<?php $model=new \frontend\models\FeedbackForm; ?>
<?php $form = ActiveForm::begin([
'enableClientValidation' => true,
'enableAjaxValidation' => true,
'validationUrl'=>['/site/feedbackvalidate'],
'validateOnSubmit' => true,
'id' => 'form-feedback',
'action'=>['/site/feedback'],
'options'=>['class'=>'some class', 'autocomplete'=>'off']
]); ?>
<?= $form->field($model, 'name')->textInput(['maxlength' => true, 'placeholder'=>$model->getAttributeLabel('name'), 'autocomplete'=>'off'])->label(false); ?>
<?= $form->field($model, 'email')->textInput(['maxlength' => true, 'placeholder'=>$model->getAttributeLabel('email'), 'autocomplete'=>'off'])->label(false); ?>
<?= $form->field($model, 'text')->textarea(['maxlength' => true, 'placeholder'=>$model->getAttributeLabel('text'), 'autocomplete'=>'off'])->label(false); ?>
<div class="form-group">
<input type="submit" class="btn btn-default" value="<?php echo Yii::t('front', 'Send') ?>">
</div>
<?php ActiveForm::end(); ?>
That is it
sorry if this has been asked before, I looked around but haven't found this specific question on StackOverFlow.com.
I have a view called 'view-post-wall' which I'm trying to add the form that submits posts to this view called 'post' via ajax submit, though I haven't begun adding ajax yet.
My module's name is 'friendicate'
I don't understand what I'm missing here, I'm following a tutorial and have been unable to get past this issue for 2 days now.
I don't get any errors either.
Here is the module code in full
function _form_post_ajax_add() {
$form = array();
$form['title'] = array(
'#type' => 'textfield',
'#title' => 'Title of post',
);
$form['body'] = array(
'#type' => 'textarea',
'#title' => 'description',
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit post',
);
return $form;
}
function post_ajax_preprocess_page(&$variables) {
//krumo($variables);
$arg = arg();
if($arg[0] == 'view-post-wall') {
$variables['page']['content']['system_main']['main']['#markup'] = drupal_render(drupal_get_form('_form_post_ajax_add'));
}
}
There are multiple ways to accomplish this, and I'll outline those methods below. Also, if nothing works from my suggestions below, it's possible that you have an invalid form function name. Im not sure if that throws off Drupal or not. The correct format for the function name should end in _form and contain the arguments $form and $form_state, like so:
_form_post_ajax_add_form($form, &$form_state) { ... }
Also, if you want to use a hook, Steff mentioned in a comment to your question that you'll need to use your module name in the function name.
friendicate_preprocess_page(&$variables) { ... }
Ok, now for a few ideas how to get the form on the page.
Block
You can create a custom block within your module, and then assign it to a region in admin/structure/blocks
<?php
/**
* Implements hook_block_info().
*/
function friendicate_block_info() {
$blocks = array();
$blocks['post_ajax'] = array(
'info' => t('Translation Set Links'),
'cache' => DRUPAL_NO_CACHE,
);
return $blocks;
}
/**
* Implements hook_block_view().
*/
function friendicate_block_view($delta = '') {
$block = array();
if ($delta == 'post_ajax') {
$form = drupal_get_form('_form_post_ajax_add_form');
$block['content'] = $form;
}
return $block;
}
Clear the cache and your block should appear in admin/structure/blocks
Views attachment before/after
You can add markup before and after a view using the Views hook hook_views_pre_render()
<?php
/**
* Implements hook_view_pre_render().
*/
function frendicate_views_pre_render(&$view) {
if($view->name == 'view_post_wall') { // the machine name of your view
$form = drupal_get_form('_form_post_ajax_add_form');
$view->attachment_before = render($form);
}
}
Or maybe use view post render
function friendicate_views_post_render(&$view, &$output, &$cache) {
//use the machine name of your view
if ($view->name == 'view_post_wall') {
$output .= drupal_render(drupal_get_form('_form_post_ajax_add'));
}
}
So basically I have a blade.php, controller page and a form request page(validation). I'm trying to keep my modal dialog open if there is an error but I just cant figure it out, what part of code am I missing out on or needs to be changed?
blade.php
<div id="register" class="modal fade" role="dialog">
...
<script type="text/javascript">
if ({{ Input::old('autoOpenModal', 'false') }}) {
//JavaScript code that open up your modal.
$('#register').modal('show');
}
</script>
Controller.php
class ManageAccountsController extends Controller
{
public $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function index()
{
$users = User::orderBy('name')->get();
$roles = Role::all();
return view('manage_accounts', compact('users', 'roles'));
}
public function register(StoreNewUserRequest $request)
{
// process the form here
$this->userRepository->upsert($request);
Session::flash('flash_message', 'User successfully added!');
//$input = Input::except('password', 'password_confirm');
//$input['autoOpenModal'] = 'true'; //Add the auto open indicator flag as an input.
return redirect()->back();
}
}
class UserRepository {
public function upsert($data)
{
// Now we can separate this upsert function here
$user = new User;
$user->name = $data['name'];
$user->email = $data['email'];
$user->password = Hash::make($data['password']);
$user->mobile = $data['mobile'];
$user->role_id = $data['role_id'];
// save our user
$user->save();
return $user;
}
}
request.php
class StoreNewUserRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
// create the validation rules ------------------------
return [
'name' => 'required', // just a normal required validation
'email' => 'required|email|unique:users', // required and must be unique in the user table
'password' => 'required|min:8|alpha_num',
'password_confirm' => 'required|same:password', // required and has to match the password field
'mobile' => 'required',
'role_id' => 'required'
];
}
}
Laravel automatically checks for errors in the session data and so, an $errors variable is actually always available on all your views. If you want to display a modal when there are any errors present, you can try something like this:
<script type="text/javascript">
#if (count($errors) > 0)
$('#register').modal('show');
#endif
</script>
Put If condition outside from script. This above is not working in my case
#if (count($errors) > 0)
<script type="text/javascript">
$( document ).ready(function() {
$('#exampleModal2').modal('show');
});
</script>
#endif
for possibly multiple modal windows you can expand Thomas Kim's code like following:
<script type="text/javascript">
#if ($errors->has('email_dispatcher')||$errors->has('name_dispatcher')|| ... )
$('#register_dispatcher').modal('show');
#endif
#if ($errors->has('email_driver')||$errors->has('name_driver')|| ... )
$('#register_driver').modal('show');
#endif
...
</script>
where email_dispatcher, name_dispatcher, email_driver, name_driver
are your request names being validated
just replace the name of your modal with "login-modal". To avoid error put it after the jquery file you linked or jquery initialized.
<?php if(count($login_errors)>0) : ?>
<script>
$( document ).ready(function() {
$('#login-modal').modal('show');
});
</script>
<?php endif ?>
I've created a widget with a CActiveForm in it. Everything works ok, but now i want to enable ajax validation for it.
The problem is that the output of my ajax validation is containing, besides the validation JSON string, all (well a part of it, since Yii::app()->end() stops the rest) of my html as well. Not weird, because i'm using it within a widget and the validation request is done to the controller/action where i've placed this widget on.
Is there some way to prevent outputting all the html, so a valid JSON string is returned?
I've already tried to set the validationUrl in the CActiveForm to another controller/action, but the problem is that i have to send the model with it and this model is determined in my widget and not on the validationUrl.
Widget:
public function run()
{
$model = new User;
$model->scenario = 'create';
$this->performAjaxValidation($model);
if (isset($_POST['User'])) {
$model->attributes = $_POST['User'];
if ($model->save()) {
}
}
$this->render('register-form', array(
'model' => $model
));
}
/**
* Performs the AJAX validation.
* #param User $model the model to be validated
*/
protected function performAjaxValidation($model)
{
if(isset($_POST['ajax']))
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
}
Output of performAjaxValidation() (the ajax call):
.. more html here ..
<section class="box">
<h1>Register form simple</h1>
{"UserPartialSignup_email":["Email is geen geldig emailadres."]}
I solved it this way:
I've created an AJAX controller where the validation is done:
AjaxController:
/**
* Validates a model.
*
* Validates a model, POST containing the data. This method is usually used for widget based forms.
*
* #param $m model name which have to be validated
* #param $s scenario for this model, optional.
* #return string JSON containing the validation data
*/
public function actionValidate($m, $s = null)
{
if ($this->checkValidationData($m, $s) && isset($_POST['ajax']))
{
$model = new $m;
$model->scenario = $s;
echo CActiveForm::validate($model);
Yii::app()->end();
} else {
throw new CHttpException(500, 'No valid validation combination used');
}
}
You can give the model name and a scenario as GET parameters with it, i'm checking if this combination is allowed by the checkValidationData() method.
In the view of my widget where the CActiveForm is placed, i've added the validationUrl, referring to ajax/validate:
widgets/views/registerform.php:
<?php $form = $this->beginWidget('CActiveForm', array(
'id'=>'signup-form-advanced',
'enableAjaxValidation'=>true,
'clientOptions' => array(
'validationUrl' => array('ajax/validate', 'm' => get_class($model), 's' => 'create')
)
//'enableClientValidation'=>true,
)); ?>