devvit icon indicating copy to clipboard operation
devvit copied to clipboard

Reddit API | Unable To Update Existing Widget

Open Beach-Brews opened this issue 10 months ago • 1 comments

Issue

The RedditAPIClient contains methods for adding, deleting and reordering sidebar Widgets. However, there is not a method for updating existing widgets, though the Widget Models appear to have create methods available (though marked with @internal).

Currently, to "update" a sidebar widget, you need to delete the existing widget, recreate the widget with changes, then potentially reorder the new widget (which is currently failing: see Issue 163). This results in 2 or 3 total API calls, instead of 1 to the existing Update Widget API.

Example Usage

import {Devvit, SettingScope, TextAreaWidget} from '@devvit/public-api';

Devvit.configure({
    redditAPI: true,
    redis: true
});

const SettingKey_SummaryWidgetName = 'summary-widget-name';

Devvit.addSettings([
    {
        type: 'string',
        name: SettingKey_SummaryWidgetName,
        label: 'The name of the summary widget',
        defaultValue: 'Summary',
        scope: SettingScope.App
    }
]);

Devvit.addSchedulerJob({
    name: 'update_community_status',
    onRun: async (event, context) => {
        if (!context.subredditName) return;

        // Find existing summary widget
        const widgetName = await context.settings.get(SettingKey_SummaryWidgetName) ?? 'Summary';
        const widgets = await context.reddit.getWidgets(context.subredditName);
        const summary = widgets
            .find(w => w.name.toLowerCase() === widgetName.toString().toLowerCase() &&
                w instanceof TextAreaWidget) as TextAreaWidget | undefined;

        // If exists, update it
        if (summary) {
            // ********** CORE ENHANCEMENT **********
            await context.reddit.updateWidget({
                type: 'textarea',
                subreddit: context.subredditName,
                id: summary.id,
                shortName: widgetName.toString(),
                text: 'Time ' + new Date().toISOString(),
                styles: {
                    backgroundColor: '',
                    headerColor: ''
                }
            });
            // ********** CORE ENHANCEMENT **********
        } else {
            // Create new if needed
            await context.reddit.addWidget({
                  type: 'textarea',
                  subreddit: context.subredditName,
                  shortName: widgetName.toString(),
                  text: 'Time ' + new Date().toISOString(),
                  styles: {
                    backgroundColor: '',
                    headerColor: ''
                  }
                });
            }
        }
    });

Devvit.addTrigger({
    event: 'AppInstall',
    onEvent: async (_, context) => {
        try {
            const jobId = await context.scheduler.runJob({
                cron: '* * * * *',
                name: 'update_community_status',
                data: {},
            });
            await context.redis.set('jobId', jobId);
        } catch (e) {
            console.log('Error: Failed to schedule update_community_status job:', e);
            throw e;
        }
    },
});

export default Devvit;

Temporary Workaround

This temporary workaround does appear to work, though "hacky" since it casts to any to get around the @internal marked method:

    const taw = TextAreaWidget as any;
    taw.update({
        id: summary.id,
        type: 'textarea',
        subreddit: context.subredditName,
        shortName: widgetName.toString(),
        text: 'Update Time ' + new Date().toISOString(),
        styles: {
          backgroundColor: '',
          headerColor: ''
        }
      });

Beach-Brews avatar Feb 10 '25 10:02 Beach-Brews

Hey @Beach-Brews , we've added context.reddit.updateWidget in @next. Let us know if you run into issues!

kay0tickay avatar Dec 04 '25 17:12 kay0tickay