2

I use the same form for adding an entry on the front end as I do for editing it.

So when editing it, we need to insert the field values in the fields.

When editing or adding it we also need to re-populate the values in the form from the POST submission in case of form validation error.

So this means checking if there is a post request, assigning the values from the post to some variables used in the form, but if not then assigning them from the entry.

I always think the method I use is a bit of a hack, and there should be some built in way to do it, but cant find it.

Below is the most efficient code I have yet but it's needed for each field. What it does is if there is a post entry then to assign it to the entry object, so that way in my form the value is just the entry.myCustomField which is set whether we're editing or posting (priority to post value if it exists).

But I wanted to know if there is an even more efficient way, something built in, or if I could even iterate through all post fields automatically without having to create the below code for each field.

{% if craft.request.getPost('fields.myCustomField') is not null %}
    {% set entry = entry|merge({'myCustomField': craft.request.getPost('fields.myCustomField')}) %}
{% endif %}

I did think maybe I could just assign the whole POST to the entry as follows which would be ideal, but I get the error 'The merge filter only works with arrays or "Traversable"'

{% if craft.request.getPost('fields') is not null %}
    {% set entry = entry|merge(craft.request.getPost('fields')) %}
{% endif %}

Another idea I had was to get all the fields from the section and iterate through them, but I don't know how I can create variables named after the values of the field handles.

{% set fields = craft.sections.getSectionByHandle('mySection').getEntryTypes()[0].getFieldLayout().getFields() %}
{% for field in fields %}
    {# dont know how to create each field named after the field.handle so I can enter my code above once and iterate over it per field #}
{% endfor %}
1

This may not be possible but can you not just make your form itself an include and have a "create" template and another "edit" template which have their own logic but include the same base form?

  • Could do but I think it adds to the complexity as I then have three template files instead of one, and I still have to use the different code to process edit or save, so I prefer to have it all in one place and assign the variables depending on where they came from, edit or save. – Laurence Cope Jan 17 at 10:26
  • I see, fair enough... then like Luke says, take peak in vendor⁩/craftcms⁩/⁨cms⁩/⁨src⁩/⁨templates⁩/⁨entries⁩ there are clues in there :) – Oli Jan 17 at 11:53
1

This might not be the perfect solution, but I think it's the way craft itself handles it:

I was recently digging through the edit template of the categories section. Craft has only one template here _edit, they therefore do the same thing as you want to: Use one template for both actions. In their template, they simply use a category object, either an empty one (if new) or an existing one. This is passed to the template by the CategoriesController.

Take a deeper look at the CategoriesController. As far as I understand, in _populateCategoryModel() they fill the elements object with the data from the request and pass it back to the template (see at actionSaveCategory).

Maybe this workaround would solve your problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.