Spaces:
Sleeping
Sleeping
File size: 5,333 Bytes
c63ff03 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
If you want users to be able to configure parts of your plugin themselves, you can expose them as _settings_.
In this guide, you'll learn how to create a settings page like this 👇
![[settings.png]]
The main reason to add settings to a plugin is to store configuration that persists even after the user quits Obsidian. The following example demonstrates how to save and load settings from disk:
```ts
import { Plugin } from "obsidian";
import { ExampleSettingTab } from "./settings";
interface ExamplePluginSettings {
dateFormat: string;
}
const DEFAULT_SETTINGS: Partial<ExamplePluginSettings> = {
dateFormat: "YYYY-MM-DD",
};
export default class ExamplePlugin extends Plugin {
settings: ExamplePluginSettings;
async onload() {
await this.loadSettings();
this.addSettingTab(new ExampleSettingTab(this.app, this));
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
}
```
> [!warning] Nested properties in settings
> `Object.assign()` copies the references to any nested properties (shallow copy). If your settings object contains nested properties, you need to copy each nested property recursively (deep copy). Otherwise, any changes to a nested property will apply do all objects that were copied using `Object.assign()`.
There's a lot going on here 🤯, so let's look closer at each part.
## Create a settings definition
First, you need to create a definition, `ExamplePluginSettings`, for what settings you want the user to be able to configure. While the plugin is enabled, you can access the settings from the `settings` member variable.
```ts
interface ExamplePluginSettings {
dateFormat: string;
}
export default class ExamplePlugin extends Plugin {
settings: ExamplePluginSettings;
// ...
}
```
## Save and load the settings object
[[loadData|loadData()]] and [[saveData|saveData()]] provide an easy way to store and retrieve data from disk. The example also introduces two helper methods that makes it easier to use `loadData()` and `saveData()` from other parts of the plugin.
```ts
export default class ExamplePlugin extends Plugin {
// ...
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
}
```
Finally, make sure to load the settings when the plugin loads:
```ts
async onload() {
await this.loadSettings();
// ...
}
```
## Provide default values
When the user enables the plugin for the first time, none of the settings have been configured yet. The preceding example provides default values for any missing settings.
To understand how this work, let's look at the following code:
```ts
Object.assign({}, DEFAULT_SETTINGS, await this.loadData())
```
`Object.assign()` is a JavaScript function that copies all properties from one object to another. Any properties that are returned by `loadData()` override the properties in `DEFAULT_SETTINGS`.
```ts
const DEFAULT_SETTINGS: Partial<ExamplePluginSettings> = {
dateFormat: "YYYY-MM-DD",
};
```
> [!tip]
> `Partial<Type>` is a TypeScript utility that returns a type with all properties of `Type` set to optional. It enables type checking while letting you only define the properties you want to provide defaults for.
## Register a settings tab
The plugin can now save and load plugin configuration, but the user doesn't yet have any way of changing any of the settings. By adding a settings tab you can provide an easy-to-use interface for the user to update their plugin settings:
```ts
this.addSettingTab(new ExampleSettingTab(this.app, this));
```
Here, the `ExampleSettingTab` is a class that extends [[PluginSettingTab|PluginSettingTab]]:
```ts
import ExamplePlugin from "./main";
import { App, PluginSettingTab, Setting } from "obsidian";
export class ExampleSettingTab extends PluginSettingTab {
plugin: ExamplePlugin;
constructor(app: App, plugin: ExamplePlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
let { containerEl } = this;
containerEl.empty();
new Setting(containerEl)
.setName("Date format")
.setDesc("Default date format")
.addText((text) =>
text
.setPlaceholder("MMMM dd, yyyy")
.setValue(this.plugin.settings.dateFormat)
.onChange(async (value) => {
this.plugin.settings.dateFormat = value;
await this.plugin.saveSettings();
})
);
}
}
```
`display()` is where you build the content for the settings tab. For more information, refer to [[HTML elements]].
`new Setting(containerEl)` appends a setting to the container element. This example uses a text field using `addText()`, but there are several other setting types available.
Update the settings object whenever the value of the text field changes, and then save it to disk:
```ts
.onChange(async (value) => {
this.plugin.settings.dateFormat = value;
await this.plugin.saveSettings();
})
```
Nice work! 💪 Your users will thank you for giving them a way to customize how they interact with your plugin. Before heading to the next guide, experiment with what you've learned by adding another setting.
|