• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.

XF 2.0 Update custom field from Widget

abdfahim

Active member
#1
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?
 

Mike

XenForo developer
Staff member
#2
Without testing, to actually do the save:
Code:
$userProfile->custom_fields->customA = $this->filter('customA', 'str');
$userProfile->save();
 

abdfahim

Active member
#3
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.');
}
 

Mike

XenForo developer
Staff member
#4
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).
 

abdfahim

Active member
#5
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.