XF 2.0 Update custom field from Widget

abdfahim

Well-known member
I show a certain custom field customA in a Widget. How can I update that custom field when someone clicks on the save button?

Code:
<xf:form action="{{ link('account/custom-save') }}" ajax="true">
   <input class="input" type="text" id="customA" name="customA" value="{$user.Profile.custom_fields.customA}">
    <xf:submitrow icon="save" />
</xf:form>

I created an actionCustomSave method to extend Account controller and tried to mimic accountSettingsSaveProcess, but that does not work, and should not be the way to do it

Code:
public function actionCustomSave(){
        $visitor = \XF::visitor();
        $form = $this->formAction();

        /** @var \XF\Entity\UserProfile $userProfile */
        $userProfile = $visitor->getRelationOrDefault('Profile');

        $this->customFieldsSaveProcess($form, 'abdforo_timeline', $userProfile);

        return $this->message('Updated.');
    }
.

Any help please?
 
Without testing, to actually do the save:
Code:
$userProfile->custom_fields->customA = $this->filter('customA', 'str');
$userProfile->save();
 
Thanks a lot @Mike, it worked nicely with your suggestion through the following code. However, I have two issues,

1) As the method actionCustomSave is defined as public, it is accessible with direct link site.com/accounts/custom-save, albeit direct access gives an error. If I change the access from Public to protected, the code can't be accessed. What is the proper way for that?

2) Is there any way I can reload the Widget (from where I am calling actionCustomSave) once it returns (sort of how Poll block works in a thread), i.e, when the message Entry saved is displayed?

Code:
public function actionCustomSave(){
        $visitor = \XF::visitor();
        $field = $this->filter('my_custom_field_id', 'str');

        /** @var \XF\Entity\UserProfile $userProfile */
        $userProfile = $visitor->getRelationOrDefault('Profile');
        $userProfile->custom_fields->set($field, $this->filter($field, 'str'));
        $userProfile->save();

        return $this->message('Entry saved.');
}
 
1. You likely want to assert that it's only accessed via POST. That will generally do what you need. See the assertPostOnly() method in controllers.

2. To do this, you'll need more custom development, both in terms of what the PHP returns (the re-rendered widget) and JS (to replace the widget).
 
Regarding (2), I successfully managed to get the job done, though most likely in a crude way, but with two issues.

What I did is, return a view from controller
Code:
public function actionCustomSave(){
        $this->assertPostOnly();
        $visitor = \XF::visitor();
      
        // Update custom field //

        $viewParams = [
            'user' => $visitor
        ];

        return $this->view('AbdFahim:CustomSaveWidget', 'reload_custom_save_widget', $viewParams);
    }

In reload_custom_save_widget template, use jQuery to change the Widget container DIV content
Code:
<script>
    jQuery( ".custom-save-widget-content" ).html("{$user.Profile.custom_fields.customB}");
</script>

Now the issues are,
1) Though the DIV content of the widget updates as intended, a blank overlay appears on screen because I returned a view from actionCustomSave method.

2) jQuery.html() method does not accept <xf:....> tag. I was trying to load a <xf:dateinput> through jQuery. This was actually posted here thinking that's not related.
 
Top Bottom