I'm having an issue with Knp, an AJAX request, and a filter. I think I'm doing something very wrong here, but I am not sure how exactly KnpPaginator works internally, and I don't have the time to figure it out on this project.
Anyway, basically, my page has an embedded controller which renders a table on the page. When paginator is called from twig, it returns the route to the container page, which results in paginator failing to work with my GET requests to that uri.
I'm not sure if any of you have come across this - I'm happy to listen if there is a better solution to the problem (I'm quite sure there is). Here is my code:
CONTROLLER
/**
* Just a shell page
*
* #Route("/postmanagement/index")
* #Template()
*
* #return array
*/
public function indexAction()
{
$form = $this->createForm(new FilterPostsType(), null, array(
'action' => $this->generateUrl('myblog_admin_postmanagement_filterposts'),
'method' => 'POST'
)
);
return array(
'form' => $form->createView()
);
}
/**
* Returns active posts and comments
*
* #param Request $request
*
* #return array
*/
public function defaultAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$posts = $em->getRepository('ModelBundle:Post')->findBy(array(
'active' => true
)
);
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate($posts, $request->query->get('page', 1), 10);
return $this->render("AdminBundle:PostManagement:_ajax-panel.html.twig", array(
'isPost' => true,
'posts' => $posts,
'pagination' => $pagination
)
);
}
/**
* #param Request $request
*
* #Route("/postmanagement/filter")
*
* #return array
*/
public function filterPostsAction(Request $request)
{
$form = $this->createForm(new FilterPostType(), null, array(
'action' => $this->generateUrl('myblog_admin_postmanagement_filterposts'),
'method' => 'POST'
)
);
// if ($request->isMethod('POST')) {
$posts = null;
$form->handleRequest($request);
$data = $form->getData();
$posts = $this->get('myblog.admin_manager')->filterPosts($data);
switch ($data['type']) {
case 'post':
$isPost = true;
$isComment = false;
break;
case 'comment':
$isPost = false;
$isComment = true;
break;
}
// }
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate($posts, $request->query->get('page', 1), $data['maxresults']);
if (is_null($posts)) {
return new NotFoundHttpException();
} else {
return $this->render('AdminBundle:PostManagement:_ajax-panel.html.twig', array(
'posts' => $posts,
'isPost' => $isPost,
'isComment' => $isComment,
'pagination' => $pagination
)
);
}
}
I'm not posting the view here, since it is a simple render(controller(MyBundle:Controller:myAction)). As you can see, there is a form I'm submitting on the page, to filter the posts. That also poses a problem, since it seems paginator doesn't keep the query after I've run it through the filter.
Thanks for any help! I would love if someone has done this before and has come up with a better solution than my rather convoluted one (which also involves too many queries for my liking).
I figured it out.
If anyone else would like to paginate with InfiScr trigger + KNPPaginatorBundle + filter (PHP), use this JS:
/**
* Load more pagination handler
*/
var AjaxPagination = function (options) {
AjaxProt.call(this, options);
this.filter = options.filter;
this.toJoinEl = options.toJoinEl;
this.containerEl = options.containerEl;
this.navContainer = options.navContainer;
this.nextSelector = options.nextSelector;
this.uri = options.uri;
};
AjaxPagination.prototype = Object.create(AjaxProt.prototype);
AjaxPagination.prototype.init = function () {
var thisObj = this,
uri = thisObj.uri;
$(thisObj.navContainer).hide();
$(document).on(thisObj.event, thisObj.targetEl, function (e) {
e.preventDefault();
thisObj.ajaxRequest(uri);
});
};
AjaxPagination.prototype.ajaxRequest = function (uri) {
var thisObj = this,
page = $(this.nextSelector).attr('href').match(/\d+$/);
$('#filter_bets_page').val(page);
var data = $(this.filter).serialize(),
method = this.method;
console.log(data);
$.ajax({
url: uri,
data: data,
type: method,
success: function (data) {
thisObj.infiScrCallback(data);
}
});
};
AjaxPagination.prototype.infiScrCallback = function(data) {
var thisObj = this;
$(thisObj.navContainer).remove();
if (thisObj.toJoinEl) {
var filteredContent = $("<div>").append( $.parseHTML( data ) ).find( '.findable');
var newPagination = $("<div>").append( $.parseHTML( data ) ).find( 'div.pagination-hidden' );
$(thisObj.toJoinEl).append(filteredContent);
$(thisObj.containerEl).append(newPagination);
} else {
$(thisObj.containerEl).append(data).fadeIn();
}
if (!$(thisObj.nextSelector).length) {
$(thisObj.targetEl).fadeOut();
}
};
Related
For a datatable I use in a page (webix datatable), I have to use a REST API.
My url is for example: http://localhost:8000/trial/1
In this page to make the api call I use the following:
save: "rest->{{ path('api_i_post') }}",
url: "rest->{{ path('erp_interventionapi_get', { trialid: trial.id })
With the GET method, I retrieve for a trial (/trial/1), many interventions which are loaded from a database and filled in the datatable.
With this datatable, I'm able to "add a new row". It uses the POST method (save: "rest->{{ path('api_i_post') }}")
When I add a new row, I'd like to be able to get the field trial_id filled in automatically, depending from where I add a new row in the datatable (for /trial/1, trial_id = 1) but I don't know how to retrieve this attribute (or the trial object id), in a POST and a PUT.
My postAction:
/**
* #Rest\Post("/api_i/", name="api_i_post")
*/
public function postAction(Request $request)
{
$data = new Intervention;
$id = $request->get('id');
$action = $request->get('action');
$daadala = $request->get('daadala');
$date = $request->get('date');
$week = $request->get('week');
$infopm = $request->get('info_pm');
$comment = $request->get('comment');
$location = $request->get('location');
$trial = $request->get('trialid');
$data->setAction($action);
$data->setDaadala($daadala);
$data->setDate($date);
$data->setWeek($week);
$data->setWho($infopm);
$data->setInfoPm($comment);
$data->setComment($location);
$data->setTrial($trial);
$em = $this->getDoctrine()->getManager();
$em->persist($data);
$em->flush();
$lastid = $data->getId();
$response=array("id" => $id, "status" => "success", "newid" => $lastid);
return new JsonResponse($response);
$view = View::create(array("newid" => $lastid, "id" => $id, "status" => "success"));
return $this->handleView($view);
}
And my putAction
/**
* #Rest\Put("/api_i/{id}")
*/
public function putAction(Request $request)
{
$data = new Intervention;
$id = $request->get('id');
$action = $request->get('action');
$daadala = $request->get('daadala');
$date = $request->get('date');
$week = $request->get('week');
$infopm = $request->get('info_pm');
$comment = $request->get('comment');
$location = $request->get('location');
$sn = $this->getDoctrine()->getManager();
$intervention = $this->getDoctrine()->getRepository('ErpBundle:Sponsor')->find($id);
if (empty($intervention)) {
return new View("Sponsor not found", Response::HTTP_NOT_FOUND);
}
$intervention->setAction($action);
$intervention->setDaadala($daadala);
$intervention->setDate($date);
$intervention->setWeek($week);
$intervention->setWho($infopm);
$intervention->setInfoPm($comment);
$intervention->setComment($location);
$sn->flush();
$response=array("id" => $id, "status" => "success");
return new JsonResponse($response);
}
Can you help me with this issue?
Thank you very much
Update of my code after the replys:
I have update this in my twig template:
save: "rest->{{ path('api_i_post', { trialid: trial.id }) }}",
If I look in the profiler of the ajax request, I see it is here:
Key Value
trialid "1"
But I still don't figure how to get it in my post request (the trial_id is still null right now)
I've tried the following:
/**
* #Rest\Post("/api_i/", name="api_i_post")
* #Rest\RequestParam(name="trialid")
*
* #param ParamFetcher $paramFetcher
* #param Request $request
*/
public function postAction(Request $request, ParamFetcher $paramFetcher)
{
$data = new Intervention;
$id = $request->get('id');
$action = $request->get('action');
$daadala = $request->get('daadala');
$date = $request->get('date');
$week = $request->get('week');
$infopm = $request->get('info_pm');
$comment = $request->get('comment');
$location = $request->get('location');
$trial = $paramFetcher->get('trialid');
$data->setAction($action);
$data->setDaadala($daadala);
$data->setDate($date);
$data->setWeek($week);
$data->setWho($infopm);
$data->setInfoPm($comment);
$data->setComment($location);
$data->setTrial($trial);
$em = $this->getDoctrine()->getManager();
$em->persist($data);
$em->flush();
$lastid = $data->getId();
$response=array("id" => $id, "status" => "success", "newid" => $lastid);
return new JsonResponse($response);
$view = View::create(array("newid" => $lastid, "id" => $id, "status" => "success"));
return $this->handleView($view);
}
I guess you are using the FosRestBundle, if so, you can use annotations to retrieve your url parameters :
/**
* #Rest\Put("/api_i/{id}", requirements={"id" = "\d+"})
*/
public function putAction($id)
{
// you now have access to $id
...
}
If you want to allow additionnal parameters for your route but not in the uri, you can use RequestParam with annotations :
/**
* #Rest\Put("/my-route/{id}", requirements={"id" = "\d+"})
*
* #Rest\RequestParam(name="param1")
* #Rest\RequestParam(name="param2")
*
* #param ParamFetcher $paramFetcher
* #param int $id
*/
public function putAction(ParamFetcher $paramFetcher, $id)
{
$param1 = $paramFetcher->get('param1');
....
}
Be sure to check the fosRestBundle documentation to see everything you can do (such as typing the params, making them mandatory or not, etc...)
To get post value you need to do this inside your post action:
public function postAction(Request $request)
{
$postData = $request->request->all();
Then you have an array of value like:
$id = $postData['id'];
For the PUT you need this:
public function putAction(int $id, Request $request)
{
$putData = json_decode($request->getContent(), true);
And then to treieve a value like this:
$id = $putData['id'];
I'm trying to create a form that would allow a manager to approve a list of time off requests (also planning to have a todo list and want to be able to mark them as done).
I have read [Generate same form type on same page multiple times Symfony2 (as well as several others) and I am close to understanding but I'm fairly to new to Symfony and not clear on what parts of the code should go in what files. I am using a form type and a controller in Symfony3 with Doctrine.
I have list of the entity instances that were returned from a query ($em->createQuery) in the controller and I am looking to produce a form for each entity instance or even two forms per entity (one for approve and one for reject).
The referenced question says you need a loop to display and save them. My intention is to only work on (submit) one at a time. I assume this part of the code would go in the controller?
I am using an indexAction for the controller but using it more like an Edit action since I will be processing forms, so I pass in a Request object and the objects as parameters.
>
class HRMgrController extends Controller
{
/**
* Lists all manager role requests and provide a means to approve/deny.
*
* #Route("/", name="hrmgr_index")
* #Method({"GET", "POST"})
* #Security("has_role('ROLE_APP_MANAGER')")
*/
public function indexAction(Request $request, TimeOffRequest $timeOffRequest)
{
if (!empty($timeOffRequest)) {
$form = $this->createForm('CockpitBundle\Form\TORApprovalType', $timeOffRequest);
print "TOR Id = " . $timeOffRequest->getId() . "<BR>";
$em = $this->getDoctrine()->getManager();
$form->handleRequest($request);
print "Form name = " . $form->getName() . "<BR>";
if ($form->isSubmitted() && $form->isValid()) {
if ($form->get('approve')->isClicked()) {
print "This puppy was approved";
$timeOffRequest['status'] = 4;
}
if ($form->get('reject')->isClicked()) {
print "This puppy was rejected";
$timeOffRequest['status'] = 1;
}
$this->getDoctrine()->getManager()->flush();
print "At least its there<BR>";
// return $this->redirectToRoute('hrmgr_index');
} else {
print "did not detect form submission<BR>";
}
}
$emp = new \CockpitBundle\Entity\Employee();
$date = new \DateTime();
$year = $date->format('Y');
$username = $this->getUser()->getUserName();
$user = $em->getRepository('CockpitBundle:Employee')->findByUsername($username);
$employees = $em->getRepository('CockpitBundle:Employee')->htmlContact($user);
$tors = $em->getRepository('CockpitBundle:TimeOffRequest')->findMgrUnapprovedTORs($user->getId());
$timeoff = "<h3>Unapproved Time Off Requests</h3>";
$actions = true;
$torforms = [];
foreach ($tors as $tor) {
$target = $this->generateUrl('hrmgr_index',array("tor_id" => $tor->getId()));
$torforms[] = $this->actionForm($tor,$target)->createView();
}
return $this->render('hrmgr/index.html.twig', array(
'torforms' => $torforms,
));
I have the forms working nowbut when I submit them the isSubmitted() doesn't seem to be working. It outputs the "did not detect form submission" currently.
So when I have multiple forms and I submit one, does the handleRequest get the right one? I think I might be confusing two concepts here as well. I recently changed the code to submit the ID of the timeOffRequest as a parameter to the route. It is properly picking that up which allows me to potentially update the form but that part of the code doesn't seem to be working.
I noticed that if I look at the debugger, I get something like:
> approval_form_2
[▼
"reject" => ""
"_token" => "IE1rGa5c0vaJYk74_ncxgFsoDU7wWlkAAWWjLe3Jr1w"
]
if I click the reject button. I get a similar form with "approve" if I click the approve button so it seems like I am close. Also, the proper ID shows up from the route given in the action.
Here is the form generator:
<?php
namespace CockpitBundle\Form;
use CockpitBundle\Entity\Employee;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class TORApprovalType extends AbstractType
{
private $nameSuffix = null;
private $name = 'time_req_approval';
public function __constructor(string $suffix = null) {
//parent::__construct();
$this->nameSuffix = $this->generateNameSuffix();
}
private function generateNameSuffix() {
if ($this->nameSuffix == null || $this->nameSuffix == '') {
$generator = new SecureRandom();
//change data to alphanumeric string
return bin2hex($generator->nextBytes(10));
}
return $this->nameSuffix;
}
public function setNameSuffix($suffix){
$this->nameSuffix = $suffix;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Build your form...
$builder->add('approve', SubmitType::class, array(
'label' => "Approve",
'attr' => array("class"=>"action-approve"),
));
$builder->add('reject', SubmitType::class, array(
'label' => "Reject",
'attr' => array("class"=>"action-reject"),
));
//$builder->add('employee');
}
public function getName() {
if ($this->nameSuffix == null || $this->nameSuffix == "" ) {
$this->nameSuffix = $this->generateNameSuffix();
}
return $this->name .'_'. $this->nameSuffix;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'CockpitBundle\Entity\TimeOffRequest'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'cockpitbundle_timeoffrequest';
}
}
Any clues? (sorry I am on vacation so not particular quick with updates.
You can do multiple submit button: check your formtype
->add('approve', 'submit')
->add('reject', 'submit')
then in your controller
if ($form->isValid()) {
// ... do something
// the save_and_add button was clicked
if ($form->get('approve')->isClicked()) {
// probably redirect to the add page again
}
if ($form->get('reject')->isClicked()) {
// probably redirect to the add page again
}
// redirect to the show page for the just submitted item
}
I was able to get it working with the following builder.
$builder->add('approve', SubmitType::class, array(
'label' => "Approve",
'attr' => array("class"=>"action-approve"),
));
$builder->add('reject', SubmitType::class, array(
'label' => "Reject",
'attr' => array("class"=>"action-reject"),
));
Then in the controller form I generate and process the forms as such. Not sure if it is the optimal way but it works find. Of course, this approach redraws the whole list each time, but that is fine for what I'm doing.
class HRMgrController extends Controller
{
/**
* Lists all manager role requests and provide a means to approve/deny.
*
* #Route("/", name="manager_home")
* #Method({"GET"})
* #Security("has_role('ROLE_APP_MANAGER')")
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$emp = new \CockpitBundle\Entity\Employee();
$employeeSummary = [];
$date = new \DateTime();
$year = $date->format('Y');
$username = $this->getUser()->getUserName();
$user = $em->getRepository('CockpitBundle:Employee')->findByUsername($username);
$myemployees = $em->getRepository('CockpitBundle:Employee')->findManagersEmployees($user);
$torRep = $em->getRepository('CockpitBundle:TimeOffRequest');
$toas = [];
$torforms = [];
foreach ($myemployees as $employee) {
$tors = $torRep->findAllMine($employee,$year);
$toas[$employee->getDisplayName()] = $em->getRepository('CockpitBundle:TimeOffAllocation')->getEmpAllocation($employee->getId(),$year);
$employeeSummary[$employee->getDisplayName()] = $torRep->mySummary($tors,$toas[$employee->getDisplayName()]);
if (array_key_exists('items',$employeeSummary[$employee->getDisplayName()]['Vacation']['Requested'])) {
foreach ($employeeSummary[$employee->getDisplayName()]['Vacation']['Requested']['items'] as $tor) {
$target = $this->generateUrl('hrmgr_tor_approval',array("tor_id" => $tor->getId()));
$torforms[] = $this->actionForm($tor,$target)->createView();
}
}
if (array_key_exists('items',$employeeSummary[$employee->getDisplayName()]['Sick Time']['Requested'])) {
foreach ($employeeSummary[$employee->getDisplayName()]['Sick Time']['Requested']['items'] as $tor) {
$target = $this->generateUrl('hrmgr_tor_approval',array("tor_id" => $tor->getId()));
$torforms[] = $this->actionForm($tor,$target)->createView();
}
}
if (array_key_exists('Time Off',$employeeSummary[$employee->getDisplayName()]) &&
array_key_exists('items',$employeeSummary[$employee->getDisplayName()]['Time Off']['Requested'])) {
foreach ($employeeSummary[$employee->getDisplayName()]['Time Off']['Requested']['items'] as $tor) {
$target = $this->generateUrl('hrmgr_tor_approval',array("tor_id" => $tor->getId()));
$torforms[] = $this->actionForm($tor,$target)->createView();
}
}
}
return $this->render('hrmgr/index.html.twig', array(
'employeeSummary' => $employeeSummary,
'torforms' => $torforms,
'year' => $year,
));
}
/**
* Lists all manager role requests and provide a means to approve/deny.
*
* #Route("/{tor_id}", name="hrmgr_tor_approval")
* #Method({ "POST" })
* #ParamConverter("timeOffRequest", class="CockpitBundle:TimeOffRequest", options={"id"="tor_id"})
* #Security("has_role('ROLE_APP_MANAGER')")
*/
public function approvalAction(Request $request, TimeOffRequest $timeOffRequest)
{
if (!empty($timeOffRequest)) {
$form = $this->createForm('CockpitBundle\Form\TORApprovalType', $timeOffRequest);
$id = $timeOffRequest->getId();
$em = $this->getDoctrine()->getManager();
$form->handleRequest($request);
$postparams = $request->request->all();
if (array_key_exists("approval_form_$id",$postparams)) {
// Form was submitted
if (array_key_exists("approve",$postparams["approval_form_$id"])) {
$status = $em->getReference('CockpitBundle\Entity\TimeOffStatus', 4);
$timeOffRequest->setStatus($status);
$timeOffRequest->setApprovedDate(new \DateTime);
$em->persist($timeOffRequest);
$em->flush($timeOffRequest);
}
if (array_key_exists("reject",$postparams["approval_form_$id"])) {
$status = $em->getReference('CockpitBundle\Entity\TimeOffStatus', 1);
$timeOffRequest->setStatus($status);
$timeOffRequest->setApprovedDate(new \DateTime);
$em->persist($timeOffRequest);
$em->flush($timeOffRequest);
}
} else {
print "Form did not exist<BR>";
}
return $this->redirectToRoute('manager_home');
}
}
public function actionForm($tor,$target) {
return $this->get('form.factory')->createNamedBuilder('approval_form_'.$tor->getId(), \CockpitBundle\Form\TORApprovalType::class, $tor,
array("action"=> $target))->getForm();
}
}
I am just starting to use Symfony and I just ran in to this problem and even after houers of research online I can not figure it out.
I am trying to insert data from a ajax request into my database. The ajax request works so far an send the following string
{"description":"","location":"","subject":"asdfasdfdsf","allDay":false,"endTime":"2016-11-22T07:00:00.000Z","startTime":"2016-11-22T06:30:00.000Z","user":"6","calendar":"1","offer":"1","status":"open"}
Here is my ajax request
$.ajax({
type: 'POST',
url: '{{ path('calendar_new') }}',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(newAppointment),
dataType: 'json',
success: function(response) {
console.log(response);
}
});
My controller looks like this
/**
* #Route("/calendar/new", name="calendar_new")
* #Method({"GET", "POST"})
*/
public function calenderNewAction(Request $request)
{
if ($request->isXMLHttpRequest()) {
$content = $request->getContent();
if (!empty($content)) {
$params = json_decode($content, true);
$new = new timeEntry;
$new->setDescription($params->get('description'));
$new->setLocation($params->get('location'));
$new->setSubject($params->get('subject'));
$new->setAllDay($params->get('allDay'));
$new->setEndTime($params->get('endTime'));
$new->setStartTime($params->get('startTime'));
$em = $this->getDoctrine()->getManager();
$calendar = $em->getRepository('AppBundle:calendar')
->findOneBy(['id' => 1]);
$offers = $em->getRepository('AppBundle:offer')
->findOneBy(['id' => 1]);
$new->setCalendar($calendar);
$new->setOffer($offers);
$new->setUser($this->getUser());
$em->persist($new);
$em->flush();
}
return new JsonResponse(array('data' => $params));
}
return new Response('Error!', 400);
}
After i try it i get the following error
Call to a member function get() on array
So the $params varible actually returns a object with all the data inside but I don't know how to set my Database variables with these values.
I figured it out.
As mentioned by Cerad I called a method on an array which was the mistake.
Here is my now working controller.
/**
* #Route("/calendar/new", name="calendar_new")
* #Method({"GET", "POST"})
*/
public function calenderNewAction(Request $request)
{
if ($request->isXMLHttpRequest()) {
$content = $request->getContent();
if (!empty($content)) {
$params = json_decode($content, true);
$new = new timeEntry;
$new->setDescription($params['description']);
$new->setLocation($params['location']);
$new->setSubject($params['subject']);
$new->setAllDay($params['allDay']);
$new->setEndTime(new \DateTime($params['endTime']));
$new->setStartTime(new \DateTime($params['startTime']));
$em = $this->getDoctrine()->getManager();
$calendar = $em->getRepository('AppBundle:calendar')
->findOneBy(['id' => 1]);
$offers = $em->getRepository('AppBundle:offer')
->findOneBy(['id' => 1]);
$new->setCalendar($calendar);
$new->setOffer($offers);
$new->setStatus('Open');
$new->setUser($this->getUser());
$em->persist($new);
$em->flush();
}
return new JsonResponse(array('data' => $params));
}
return new Response('Error!', 400);
}
I’m trying to get my Ajax-Function to call a certain controller inside my Typo3 extension.
After several attempts, I decided to go with the same Ajax-Dispatcher that powermail uses. It does show an output, but it completely ignores the supposed controller and action.
There are two Controllers in my Extension and so far three actions:
Category=>list
Family=>list,compare
PHP:
<?php
namespace Vendor\Myextension\Utility;
use \TYPO3\CMS\Core\Utility\GeneralUtility;
class AjaxDispatcher {
/**
* configuration
*
* #var \array
*/
protected $configuration;
/**
* bootstrap
*
* #var \array
*/
protected $bootstrap;
/**
* Generates the output
*
* #return \string rendered action
*/
public function run() {
return $this->bootstrap->run('', $this->configuration);
}
/**
* Initialize Extbase
*
* #param \array $TYPO3_CONF_VARS The global array. Will be set internally
*/
public function __construct($TYPO3_CONF_VARS) {
$this->configuration = array(
'pluginName' => 'my_plugin',
'vendorName' => 'Vendor',
'extensionName' => 'myextension',
'controller' => 'Family',
'action' => 'compare',
'mvc' => array(
'requestHandlers' => array(
'TYPO3\CMS\Extbase\Mvc\Web\FrontendRequestHandler' => 'TYPO3\CMS\Extbase\Mvc\Web\FrontendRequestHandler'
)
),
'settings' => array()
);
$_POST['request']['action'] = 'compare';
$_POST['request']['controller'] = 'Family';
$this->bootstrap = new \TYPO3\CMS\Extbase\Core\Bootstrap();
$userObj = \TYPO3\CMS\Frontend\Utility\EidUtility::initFeUser();
$pid = (GeneralUtility::_GET('id') ? GeneralUtility::_GET('id') : 1);
$GLOBALS['TSFE'] = GeneralUtility::makeInstance(
'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController',
$TYPO3_CONF_VARS,
$pid,
0,
TRUE
);
$GLOBALS['TSFE']->connectToDB();
$GLOBALS['TSFE']->fe_user = $userObj;
$GLOBALS['TSFE']->id = $pid;
$GLOBALS['TSFE']->determineId();
$GLOBALS['TSFE']->getCompressedTCarray();
$GLOBALS['TSFE']->initTemplate();
$GLOBALS['TSFE']->getConfigArray();
$GLOBALS['TSFE']->includeTCA();
}
}
$eid = GeneralUtility::makeInstance('Vendor\Myextension\Utility\AjaxDispatcher', $GLOBALS['TYPO3_CONF_VARS']);
echo $eid->run();
Ajax:
var read = 'string';
var requestData = {'value': read};
var currentUrl = window.location;
$.ajax({
url: currentUrl,
type: 'POST',
data: {
eID: "ajaxDispatcherMyextension",
request: {
controller: 'Family',
action: 'compare',
arguments: {
'test': requestData
}
}
},
dataType: 'html',
success: function(success) {
console.log('success ' + success);
$('#test').html(success);
}
});
Instead of showing family->compare the Ajax puts out category->compare. I don’t understand why.
Can someone please help? I'm working on this problem for over 2 days now...
I don't know exactly what you mean. If you want to trigger an AJAX request while clicking on a link you can do the following in the belonging view of your action. In this example the script will output the AJAX response.
1) Create a ViewHelper containing something like that:
$uriBuilder = $this->controllerContext->getUriBuilder();
$uri = $uriBuilder->uriFor(
'title',
array("param1" => $value1, "param2" => $value2),
'<controllerName>',
'<extKey>',
'<pluginName>');
return '<a id="link" href="'.$uri.'">';
2) Call the ViewHelper in your view template and add a output container div with an id.
3) Implement the JavaScript for AJAX call
function loadurl(dest, obj) {
try {
xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
console.log(e);
}
xmlhttp.onreadystatechange = function() {
triggered(obj);
};
xmlhttp.open("GET", dest);
xmlhttp.send(null);
}
function triggered(obj) {
if ((xmlhttp.readyState == 4) && (xmlhttp.status == 200)) {
document.getElementById(obj).innerHTML = xmlhttp.responseText;
}
}
window.addEventListener("load", function() {
var item = document.getElementsById('link');
item.addEventListener('click', function(event) {
event.preventDefault();
var href = this.childNodes[1].getAttribute("href");
loadurl(href, 'idOfOutputContainer');
}
}
It's not implemented in 6.2 as noted in my bug report: action and controller not used in RequestBuilder.php:loadDefaultValues
Hi I am using a SAutoComplete (extends CAutoComplete) and need to do some work when a value is selected from the list.
i am using it like this.
this->widget('application.components.SAutoComplete', array('width'=>200,
'model'=>$cssAtapsClient, 'parseData'=>true, 'matchContains'=>true,
'attribute'=>'suburb_id', 'data'=>$postCode, 'ddindicator'=>true,
'max'=>50,
'multipleSeparator'=>false,
'options' => array(
'select' => new CJavaScriptExpression('function(e, ui) { alert("hi"); }')
),
)); ?>
i am wondering why there is no select option like available in jquery UI auto completed?
example of a select is as below.
$("#auto_cp").autocomplete({
minLength: 3,
//source
source: function(req, add) {
$.getJSON("friends.php?callback=?", req, function(data) {
var suggestions = [];
$.each(data, function(i, val) {
suggestions.push({
label: val.name,
zzz: val.zzz
});
});
add(suggestions);
});
},
//select
select: function(e, ui) {
alert(ui.item.zzz);
}
});
EDIT 2
http://www.yiiframework.com/doc/api/1.1/CAutoComplete
code is like this,
<?php
class SAutoComplete extends CAutoComplete
{
public $ddindicator;
/**
*
* #var boolean whether to parse the data assumes data uses an assoc array
* array(value => array(name, value, ...), ...). Only works with a model present
*/
public $parseData;
/**
* #var boolean whether to raise the change event
*/
public $raiseChangeEvent = false;
/**
* Initializes the widget.
* This method registers all needed client scripts and renders
* the autocomplete input.
*/
public function init()
{
if ( !$this->max )
$this->max = 50000;
if ( $this->ddindicator )
$this->alternateInit();
else
parent::init();
}
public function alternateInit()
{
list($name,$id)=$this->resolveNameID();
$this->htmlOptions['id'] = $id.'_input';
$this->minChars = 0;
echo CHtml::openTag('div', array('class'=>'ac-input-dd'));
echo CHtml::openTag('div', array('class'=>'ac-input-btn'));
echo CHtml::closeTag('div');
if($this->hasModel())
{
$htmlOpt = array();
if ( $this->parseData )
{
$menu = $this->data;
$key = $this->attribute;
//Change if attribute is apart of a array. eg attribute[0]
$pos1 = stripos($key, '[');
$pos2 = stripos($key, ']');
if($pos1!==false && $pos2!==false)
{
$key = str_replace (substr($key,$pos1,$pos2 - $pos1 + 1),'',$key);
$htmlOpt['value'] = isset($this->model->$key) ? $this->model->$key : '';
}
$this->value = isset($menu[$this->model->$key][0]) ? $menu[$this->model->$key][0] : '';
$this->data = is_array($menu) ? array_values($menu) : array('Error in data.');
}
echo CHtml::activeHiddenField($this->model, $this->attribute, array_merge(array('id'=>$id, 'name'=>$name), $htmlOpt));
echo CHtml::textField('', $this->value, $this->htmlOptions);
}
else
{
echo CHtml::hiddenField($name, $this->value, array('id'=>$id));
echo CHtml::textField($name.'_input',$this->value,$this->htmlOptions);
}
echo CHtml::closeTag('div');
$this->methodChain = $this->methodChain.'.result(function(evt, data, formatted) { $("#'.
$id.'").val(data ? data[1] : "")'.($this->raiseChangeEvent?'.change()':'').'; })'.
'.parent().find(".ac-input-btn").mousedown(function(){'.
'jQuery(this).parent().find(".ac_input").toggleResults();})'.
'.mouseup(function(){jQuery(this).parent().find(".ac_input").focus();});';
$this->registerClientScript();
}
public static function registerScript()
{
$cs = Yii::app()->getClientScript();
$cs->registerCoreScript('jquery');
$cs->registerCoreScript('bgiframe');
TK::registerScriptFile('autocomplete');
$cs->registerCssFile($cs->getCoreScriptUrl().'/autocomplete/jquery.autocomplete.css');
}
/**
* Registers the needed CSS and JavaScript.
* #since 1.0.1
*/
public function registerClientScript()
{
// can cut this down once YII releases a fix for defect #38
if ( Yii::app()->request->isAjaxRequest || $this->ddindicator )
{
$id=$this->htmlOptions['id'];
$acOptions=$this->getClientOptions();
$options=$acOptions===array()?'{}' : CJavaScript::encode($acOptions);
$cs=Yii::app()->getClientScript();
if($this->data!==null)
$data=CJavaScript::encode($this->data);
else
{
$url=CHtml::normalizeUrl($this->url);
$data='"'.$url.'"';
}
if ( Yii::app()->request->isAjaxRequest )
{
echo '<script type="text/javascript">jQuery(document).ready('.
'function() {jQuery("#'.$id.'").autocomplete('.$data.','.$options.')'.
$this->methodChain.';});</script>';
}
else
{
SAutoComplete::registerScript();
$cs->registerScript('Yii.CAutoComplete#'.$id,"jQuery(\"#{$id}\").autocomplete($data,{$options}){$this->methodChain};");
}
}
else
parent::registerClientScript();
}
}
You can pass any option that the JUI autocomplete widget supports by including an options array:
$this->widget('zii.widgets.jui.CJuiAutoComplete', array(
// your other settings here
'options' => array(
'select' => new CJavaScriptExpression('function(e, ui) { alert("hi"); }')
),
));
If the options you want to pass include JavaScript code then you also have to wrap that inside a CJavaScriptExpression as above.
Try to add this,
'methodChain'=>".result(function(event,item){ urFunction(); })",
Have a nice day!
So at last it will look like,
$this->widget('application.components.SAutoComplete', array('width'=>200,
'model'=>$cssAtapsClient, 'parseData'=>true, 'matchContains'=>true,
'attribute'=>'suburb_id', 'data'=>$postCode, 'ddindicator'=>true,
'max'=>50,
'methodChain'=>".result(function(event,item){ urFucntion(); })",
));
I'm using CAutoComplete as the followin code:
In post/_form.php
<?php $this->widget('CAutoComplete', array(
'model' => $model,
'attribute' => 'tags',
'url' => array('suggestTags'),
'multiple' => true,
'htmlOptions' => array(
'size' => 50,
'class' => 'span11'
),
)); ?>
In PostController.php
Add one more action call: suggestTags
/**
* Suggests tags based on the current user input.
* This is called via AJAX when the user is entering the tags input.
*/
public function actionSuggestTags()
{
if(isset($_GET['q']) && ($keyword=trim($_GET['q']))!=='')
{
$tags=Tag::model()->suggestTags($keyword);
if($tags!==array())
echo implode("\n",$tags);
}
}
In Post.php model
add private $_oldTags; to the top of class (under class name).
add these functions:
/**
* Normalizes the user-entered tags.
*/
public function normalizeTags($attribute, $params)
{
$this->tags = Post::array2string(array_unique(Post::string2array($this->tags)));
}
public static function string2array($tags)
{
return preg_split('/\s*,\s*/', trim($tags), -1, PREG_SPLIT_NO_EMPTY);
}
public static function array2string($tags)
{
return implode(', ', $tags);
}
See more Yii tutorials here