Can I use the same view for a different action? - php

I have controller, 'products', with the actions 'add' and 'edit'.
I made the view 'add.ctp' which has a long form. Was wondering if I can use that same view for generating display 'edit'. What would I need to put in the controller, under edit() {}, to make it output to 'add.ctp' instead of 'edit.ctp'?
Thanks.

You could use:
$this->render('add');
at the end of your controller's edit function, but I wouldn't recommend it.
A better solution would be to do a small refactor to put the contents of your add.ctp into an element (e.g. app/views/elements/productForm.ctp), and then use that element from both the add.ctp and edit.ctp views.
<?php echo $this->element('productForm'); ?>
This gives you the flexibility to wrap the form with action specific elements, and do any setup that might be specific to that action. For example, under the product form you might have a different set of actions, such as "View Product" that doesn't make sense in add mode but does in edit mode.
#kaklon made a very good point, you should put a little bit of logic into the productForm element to make sure edit mode behaves correctly:
if ($this->action == 'edit') {
echo $this->Form->input('id');
}

Pseudocoder wrote a very good article on this: http://www.pseudocoder.com/archives/category/cakephp/page:4
He has since improved this even more by using routes to eliminate the add action altogether I think. You may be interested in his compilation of CakePHP tips & hacks: http://www.pseudocoder.com/free-cakephp-book/

yes you can, This is one way to do it... https://github.com/infinitas/infinitas/blob/dev/app_controller.php#L374
that allows you to use one file when there is only one available, or add/edit when you need different stuff

You are looking for elements. The view is not 100% identical, because the edit form needs to contain the id of the product you want to edit, while the add form does not have an id..

Related

First postLink() doesn't create form

Using code that has been baked into CRUD, I have the following code for deleting an item:
<?php echo $this->Form->postLink(__('Delete'), array('controller'=>'attachments', 'action' => 'delete', $attachment['Attachment']['id']), null, __('Are you sure you want to delete "%s?"', $attachment['Attachment']['name'])); ?>
The problem is that it lies wrapped in a FORM tag, and so what ends up happening is Cake doesn't include the Form that the postLink would submit.
Is there another way that still holds true to the integrity of Cake's infrastructure that would work even when I increase the security settings? Probably needs to be a link to /attachment/delete/id, but baking for some reason chose to create a form and post it vs. creating a link, so I figured there was a reason for that and if so I want to uphold that reason.
You probably didn't read the warnings in the doc block regarding this method
(http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::postLink)
This method creates a <form> element. So do not use this method inside an existing form.
Instead you should add a submit button using FormHelper::submit()
So don't do that. You would need to write to a buffer and output later (see this closed PR).
I have the same problem in cakephp 3.0 $this->Form->postLink() was not working for first entry.
Then i do some R&D but not found any useful. Then i make some changes in form tag and $this->Form->postLink(). I remove the $this->Form->create() from the .ctp files and use only $this->Form->postLink(); and it start working.
Do not use the $this->Form->postLink() inside any other form tag
i.e $this->Form->create(null, ['url' => ['action' => 'ExportCustomers']]);
If you want both then you have to adjust the $this->Form->postLink() and form tag according to it will not effect each other.

Codeigniter PHP - loading a view at an anchor point

I have a form at the bottom of a long page, if a user fills out the form but it doesn't validate the page is reloaded in the typical codeigniter fashion:
$this->load->view('template',$data);
however because the form is way down at the bottom of the page I need the page to load down there like you do with HTML anchors. Does anyone know how to do this in codeigniter?
I can't use the codeigniter
redirect();
function because it loses the object and the validation errors are gone. Other frameworks I've used like Yii you can call the redirect function like:
$this->redirect();
which solves the problem because you keep the object. I've tried using:
$this->index()
within the controller which works fine as a redirect but the validation errors are in another method which is where the current page is loaded from:
$this->item($labs)
but when I use this it get stuck in a loop
Any ideas? I've seen this question a lot on the net but no clear answers. I'm researching using codeigniter "flash data" but think it's a bit overkill.
cheers.
I can't personally vouch for this, but according to this thread if you append the anchor to the form's action, it will work.
CodeIgniter helper:
<?php echo form_open('controller/function#anchor'); ?>
Or vanilla HTML:
<form method='post' action='controller/function#anchor'>
If you were open to using Javascript, you could easily detect a $validation_failed variable and appropriately scroll. Or, even better, use AJAX.
Another option is to put the form near the top of the page?
Ok, as far as I understood your problem, it isn't much related to the back end(codeigniter). You want the form at the bottom of the page to be 'what-users-sees-on-page-load' (since you mention anchors).
Now, what you can do is, you can set delimiters for your validation error messages using:
echo validation_errors('<div id="bottom_form_error">', '</div>');
Using jQuery ScrollTo, do:
$( function() { $('#bottom_form_error').ScrollTo(); } );
And, the user will be scrolled to the errors at the bottom of the page. Don't forget to include jQuery too.
Anchor hash fragment click is different - it is scrolling at ∞ speed.
I hope that is what you wanted.
P.S. I am ignoring what you said below this line:
Does anyone know how to do this in codeigniter?
as I felt it is not really relevant to the question.

Yii ajaxLink() only works once

I have a CListView that uses ajaxLink() in the _view file.
View (index.php)
<?php
Yii::app()->clientScript->registerScript('ajaxUpdate',
"
//javascript function to update the listview using ajax
function updateItemList(){
$.fn.yiiListView.update('itemList');
return false;
}
", CClientScript::POS_READY);
?>
<?php $this->widget('zii.widgets.CListView', array(
'dataProvider'=>$dataProvider,
'itemView'=>'_view',
'id'=>'itemList',
)); ?>
partial (_view.php)
<?php echo CHtml::ajaxLink('Delete',array('libdbitems/delete','id'=>$data->id),
array('type'=>'POST','success'=>'function(){updateItemList()}'),
array('confirm'=>'Are you sure you want to delete this item?',
'id'=>'delete-'.$data->id)); ?>
The controller is basically just the default actionIndex() that is generated with Gii.
Here's the problem: when I click my Delete link the first time after a page load, it behaves as expected. After that, clicking Delete does nothing. (It refreshes the ListView, but no changes are made.)
I'm pretty sure the problem lies in how Yii is binding click() events to my links in javascript, but I have no idea how to fix it. I have tried using the live=true option as others have suggested, but it does nothing.
Does anyone know how to fix this issue so that my Delete link works multiple times without having to reload the page?
Is your delete link part of the itemlist that's refreshed? If that's the case, the script won't re-register with the new link when a new link is created.
Two options:
1) Make sure your link is not being refreshed, and is a permanent aspect of the page
2) Write a custom jQuery handler rather than using Yii's ajaxLink. You'll need to use .on and delegated events. Something of the form:
$("#parentContainer").on("click", ".deleteLinkClass', updateItemList)
Where the parentContainer is a permanent item on the page, and deleteLinkClass will be a class you'll need to assign to the delete links you're using.
Eh, a stupid fix. I realized I had accidentally left a CHtml::$liveEvents = false in my controller that I put there while I was still earlier in the troubleshooting phase.
The solution is just to leave CHtml::$liveEvents = true (default) and to make sure all the links have unique IDs.

Yii - generating a URL while preserving or deleting GET parameters

I currently have a view, manage, that lists data items. Instead of running "edit" and "add" actions with separate views, I'm having the appropriate form display inline in the page when it is needed. On the form is a "cancel" button that will hide it.
Right now I decide what, if any, form to display inline through a GET parameter called mode. So /controller/manage will display the items, while /controller/manage?mode=edit will display the items and show the edit form for the correct data item.
The action accepts various other GET parameters such as a date interval.
In order to activate the form, I'm generating a link to the current action with the mode parameter spliced in with existing parameters in $_GET. I'm using the following one-liner:
<?php echo CHtml::link('Edit', array_merge(array('/session/manage', 'mode' => 'edit', 'id' => 6), $_GET)); ?>
To implement the "cancel" link, I'm using:
<?php echo CHtml::link('Cancel', array_diff(array_merge(array('/session/manage'), $_GET), array('edit'))); ?>
My question is: is there a cleaner way to do this? While this works, it feels like a hack. I haven't found any documentation on generating URLs that include existing GET parameters. Does Yii provide a built-in method to do what I want to do? Should I re-evaluate my general approach to conditional views, which might in turn yield a cleaner solution?
One way would be to hold all of the most recent _GET variables in session state. Your controller would then act on that stored data and use new _GET variables to override it. Using that method, you wouldn't need to merge the existing _GET variables back into the new request. The tradeoff is that you end up having to manage that session data and handle possible special cases (like starting over with fresh state).
Another way would be to use Ajax to call an action that returns a partial view with your rendered edit form. Then your links would just need to call some javascript that does the Ajax call with the current ID and displays the returned form on the page. Your links would end up looking something like this:
<a href="#" onclick="showEdit(6)">
Since using Ajax wouldn't cause the page to reload, you don't need to worry about any of the _GET parameters required to show your list. And your Cancel link would become a javascript call to simply remove the edit form from the DOM. Using jQuery:
$('#editform').remove();
Another way to make it a little cleaner would be to encapsulate all of the array_merge() stuff up there into a method of a custom component or helper. Then your code could look something like:
echo CHtml::link('Edit', URLHelper::mergeGet(array('/session/manage', 'mode' => 'edit', 'id' => 6));
or even ecapsulate that in your own CHtml class:
echo MyCHtml::link('Edit', array('/session/manage', 'mode' => 'edit', 'id' => 6));
where MyCHtml::link() does everything that CHtml::link() does in addition to the array_merge stuff. MyCHtml could even extend CHtml so that it has all of CHtml's methods.

Symfony embedded form - possible to NOT show embedded form's "parent" label?

When you embed a form in Symfony, a label for the embedded form is injected into the parent form. For example: If I have a PersonForm and add this code $this->embedForm('Address', $addressForm), my PersonForm will now have an 'Address' label within it, in addition to the labels for the fields that make up the AddressForm. I'd like to keep the labels for the individual fields, but get rid of the 'Address' label, thereby making it appear that the two forms are really one.
It's possible to override the form template and manually iterate over the form elements and echo them one by one, but I run into this situation frequently and I'd prefer to have Symfony handle this automatically.
The following code will allow you to set the label to another an empty string but I suspect it would still appear anyway.
$this->embedForm('Address', $addressForm)
$this->widgetSchema['Address']->setLabel('');
however I suspect the best thing to use is to look at point 6 (embedMergeForm) on this page and use that http://itsmajax.com/2011/01/29/6-things-to-know-about-embedded-forms-in-symfony/
Given your situation, iterating manually over the widgets is the only option. The other option is extending sfWidgetFormSchemaFormatter, but that won't allow hiding a label for an embedded form, while at the same time not hiding it for any other widget.
If you do run into this situation often, you could consider creating a partial just for rendering your form in this specific way.
Here is a simple way of disabling all labels. Add this method to BaseForm if you do it frequently.
public function disableLabels()
{
$fields = $this->getWidgetSchema()->getFields();
$this->getWidgetSchema()->setLabels(array_combine(array_keys($fields), array_fill(0, count($fields), false)));
}
If you only want to disable labels in the embedded form, disable them before embedding:
$form = new FormToEmbed();
$form->disableLabels();
$parent->embedForm('child', $form);

Categories