or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

base-components.mdcomponent-properties.mddependency-injection.mdindex.mdlifecycle-events.md

lifecycle-events.mddocs/

0

# Lifecycle and Events

1

2

Decorators for handling component lifecycle events and custom event emission. These decorators provide reactive data observation and automatic event emission patterns for Vue class-based components.

3

4

## Capabilities

5

6

### Watch Decorator

7

8

Creates reactive watchers for data properties, enabling components to respond to changes in data, props, or computed properties.

9

10

```typescript { .api }

11

/**

12

* Creates reactive watchers for data properties

13

* @param path - Property path or expression to observe (required)

14

* @param options - WatchOptions object (optional, defaults to {})

15

* @returns Method decorator function

16

*/

17

function Watch(path: string, options: WatchOptions = {}): MethodDecorator;

18

19

interface WatchOptions {

20

deep?: boolean;

21

immediate?: boolean;

22

}

23

```

24

25

**Usage Examples:**

26

27

```typescript

28

import { Vue, Component, Watch, Prop } from "vue-property-decorator";

29

30

@Component

31

export default class MyComponent extends Vue {

32

@Prop()

33

count!: number;

34

35

localData = 0;

36

user = { name: "", age: 0 };

37

38

// Basic watcher

39

@Watch("count")

40

onCountChanged(newVal: number, oldVal: number) {

41

console.log(`count changed from ${oldVal} to ${newVal}`);

42

}

43

44

// Deep watcher for objects

45

@Watch("user", { deep: true })

46

onUserChanged(newUser: any, oldUser: any) {

47

console.log("User object changed:", newUser);

48

}

49

50

// Immediate watcher (executes on component creation)

51

@Watch("localData", { immediate: true })

52

onLocalDataChanged(newVal: number, oldVal: number) {

53

if (newVal > 10) {

54

this.$emit("threshold-exceeded", newVal);

55

}

56

}

57

58

// Watch nested properties

59

@Watch("user.name")

60

onUserNameChanged(newName: string, oldName: string) {

61

console.log(`User name changed from ${oldName} to ${newName}`);

62

}

63

64

// Watch computed properties

65

get fullName() {

66

return `${this.user.name} (${this.user.age})`;

67

}

68

69

@Watch("fullName")

70

onFullNameChanged(newFullName: string) {

71

console.log("Full name updated:", newFullName);

72

}

73

}

74

```

75

76

### Emit Decorator

77

78

Automatically emits events with method return values and arguments, providing a declarative way to handle component event emission.

79

80

```typescript { .api }

81

/**

82

* Automatically emits events with method return values and arguments

83

* @param event - Event name (optional, defaults to kebab-case method name)

84

* @returns Method decorator function

85

*/

86

function Emit(event?: string): MethodDecorator;

87

```

88

89

**Usage Examples:**

90

91

```typescript

92

import { Vue, Component, Emit } from "vue-property-decorator";

93

94

@Component

95

export default class MyComponent extends Vue {

96

count = 0;

97

98

// Basic emit - event name defaults to kebab-case method name

99

@Emit()

100

increment() {

101

this.count++;

102

return this.count; // Emitted as first argument

103

}

104

105

// Custom event name

106

@Emit("custom-event")

107

handleCustomAction() {

108

return { timestamp: Date.now(), action: "custom" };

109

}

110

111

// Emit with method arguments

112

@Emit("user-updated")

113

updateUser(name: string, age: number) {

114

// Method arguments are emitted after return value

115

return { success: true }; // Emitted as [{ success: true }, "name", age]

116

}

117

118

// Emit without return value

119

@Emit("button-clicked")

120

handleClick() {

121

// No return value, only method arguments are emitted

122

console.log("Button was clicked");

123

}

124

125

// Emit with Promise return value

126

@Emit("async-complete")

127

async performAsyncAction() {

128

const result = await this.fetchData();

129

return result; // Promise result is awaited and then emitted

130

}

131

132

// Complex emit with multiple arguments

133

@Emit("data-processed")

134

processData(input: any[], options: any) {

135

const processed = input.map(item => ({ ...item, processed: true }));

136

return {

137

processed,

138

originalCount: input.length,

139

processedCount: processed.length

140

};

141

// Emits: [returnValue, input, options]

142

}

143

144

private async fetchData() {

145

// Simulate async operation

146

return new Promise(resolve => {

147

setTimeout(() => resolve({ data: "fetched" }), 1000);

148

});

149

}

150

}

151

```

152

153

## Advanced Usage Patterns

154

155

### Form Validation with Watchers

156

157

```typescript

158

import { Vue, Component, Watch, Prop } from "vue-property-decorator";

159

160

@Component

161

export default class ValidationForm extends Vue {

162

@Prop({ required: true })

163

initialData!: any;

164

165

formData = {

166

email: "",

167

password: "",

168

confirmPassword: ""

169

};

170

171

errors: any = {};

172

173

@Watch("formData.email")

174

validateEmail(email: string) {

175

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

176

this.errors.email = emailRegex.test(email) ? null : "Invalid email format";

177

}

178

179

@Watch("formData.password")

180

validatePassword(password: string) {

181

this.errors.password = password.length >= 8 ? null : "Password must be at least 8 characters";

182

// Re-validate confirm password when password changes

183

this.validateConfirmPassword(this.formData.confirmPassword);

184

}

185

186

@Watch("formData.confirmPassword")

187

validateConfirmPassword(confirmPassword: string) {

188

this.errors.confirmPassword =

189

confirmPassword === this.formData.password ? null : "Passwords do not match";

190

}

191

192

@Watch("initialData", { immediate: true, deep: true })

193

loadInitialData(data: any) {

194

if (data) {

195

this.formData = { ...data };

196

}

197

}

198

}

199

```

200

201

### Event Chain with Emit

202

203

```typescript

204

import { Vue, Component, Emit, Watch } from "vue-property-decorator";

205

206

@Component

207

export default class DataProcessor extends Vue {

208

rawData: any[] = [];

209

processing = false;

210

211

@Watch("rawData")

212

onDataChanged(newData: any[]) {

213

if (newData.length > 0) {

214

this.startProcessing();

215

}

216

}

217

218

@Emit("processing-started")

219

startProcessing() {

220

this.processing = true;

221

return { timestamp: Date.now(), itemCount: this.rawData.length };

222

}

223

224

@Emit("item-processed")

225

processItem(item: any, index: number) {

226

// Simulate processing

227

const processed = { ...item, processed: true, index };

228

return processed;

229

}

230

231

@Emit("processing-complete")

232

completeProcessing() {

233

this.processing = false;

234

return {

235

timestamp: Date.now(),

236

totalProcessed: this.rawData.length,

237

success: true

238

};

239

}

240

241

@Emit("processing-error")

242

handleProcessingError(error: Error) {

243

this.processing = false;

244

return { error: error.message, timestamp: Date.now() };

245

}

246

}

247

```

248

249

### Real-time Data Synchronization

250

251

```typescript

252

import { Vue, Component, Watch, Emit } from "vue-property-decorator";

253

254

@Component

255

export default class RealTimeSync extends Vue {

256

localData: any = {};

257

syncEnabled = true;

258

lastSyncTime = 0;

259

260

@Watch("localData", { deep: true })

261

onLocalDataChanged(newData: any, oldData: any) {

262

if (this.syncEnabled && this.hasSignificantChanges(newData, oldData)) {

263

this.scheduleSync();

264

}

265

}

266

267

@Watch("syncEnabled")

268

onSyncToggled(enabled: boolean) {

269

if (enabled) {

270

this.performSync();

271

}

272

}

273

274

@Emit("sync-requested")

275

scheduleSync() {

276

// Debounce sync requests

277

clearTimeout(this.syncTimer);

278

this.syncTimer = setTimeout(() => {

279

this.performSync();

280

}, 1000);

281

return { data: this.localData, scheduled: true };

282

}

283

284

@Emit("sync-complete")

285

async performSync() {

286

try {

287

await this.syncToServer(this.localData);

288

this.lastSyncTime = Date.now();

289

return { success: true, timestamp: this.lastSyncTime };

290

} catch (error) {

291

this.handleSyncError(error);

292

}

293

}

294

295

@Emit("sync-error")

296

handleSyncError(error: any) {

297

return { error: error.message, timestamp: Date.now() };

298

}

299

300

private syncTimer: any;

301

302

private hasSignificantChanges(newData: any, oldData: any): boolean {

303

// Implementation for determining significant changes

304

return JSON.stringify(newData) !== JSON.stringify(oldData);

305

}

306

307

private async syncToServer(data: any): Promise<void> {

308

// Implementation for server synchronization

309

return new Promise((resolve) => {

310

setTimeout(resolve, 500); // Simulate network delay

311

});

312

}

313

}

314

```

315

316

## Types

317

318

```typescript { .api }

319

interface WatchOptions {

320

deep?: boolean;

321

immediate?: boolean;

322

}

323

324

type MethodDecorator = (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void;

325

```