Skip to content

Commit

Permalink
MOBILE-4612 compile: Expose model and untracked to plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
dpalou committed Jul 31, 2024
1 parent ba0f71d commit 9f910d3
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 13 deletions.
19 changes: 6 additions & 13 deletions src/core/features/compile/services/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ import {
ViewContainerRef,
signal,
computed,
effect,
EffectCleanupRegisterFn,
CreateEffectOptions,
EffectRef,
untracked,
} from '@angular/core';
import {
ActionSheetController,
Expand All @@ -41,6 +38,7 @@ import { TranslateService } from '@ngx-translate/core';
import { CoreLogger } from '@singletons/logger';
import { CoreEvents } from '@singletons/events';
import { makeSingleton } from '@singletons';
import { effectWithInjectionContext, modelWithInjectionContext } from '@/core/utils/signals';

// Import core services.
import { getCoreServices } from '@/core/core.module';
Expand Down Expand Up @@ -306,15 +304,10 @@ export class CoreCompileProvider {
instance['Md5'] = Md5;
instance['signal'] = signal;
instance['computed'] = computed;
// Create a wrapper to call effect with the proper injection context.
instance['effect'] = (
effectFn: (onCleanup: EffectCleanupRegisterFn) => void,
options?: Omit<CreateEffectOptions, 'injector'>,
): EffectRef =>
effect(effectFn, {
...options,
injector,
});
instance['untracked'] = untracked;
instance['effect'] = effectWithInjectionContext(injector);
instance['model'] = modelWithInjectionContext(injector);

/**
* @deprecated since 4.1, plugins should use CoreNetwork instead.
* Keeping this a bit more to avoid plugins breaking.
Expand Down
73 changes: 73 additions & 0 deletions src/core/utils/signals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import {
CreateEffectOptions,
effect,
EffectCleanupRegisterFn,
EffectRef,
Injector,
model,
ModelOptions,
ModelSignal,
runInInjectionContext,
} from '@angular/core';

/**
* Return an effect wrapper that can be used to create an effect with a certain injection context.
* Example:
*
* ```
* const effectWrapper = effectWithInjectionContext(injector);
*
* effectWrapper(() => {
* // Your effect code here.
* });
* ```
*
* @param injector Injector to use for the effect.
* @returns Function to create the effect.
*/
export function effectWithInjectionContext(injector: Injector): typeof effect {
return (
effectFn: (onCleanup: EffectCleanupRegisterFn) => void,
options?: Omit<CreateEffectOptions, 'injector'>,
): EffectRef =>
effect(effectFn, {
...options,
injector,
});
}

/**
* Return a model wrapper that can be used to create a model with a certain injection context.
* Example:
*
* ```
* const modelWrapper = modelWithInjectionContext(injector);
*
* const myModel = modelWrapper('');
* ```
*
* @param injector Injector to use for the model.
* @returns Function to create the model.
*/
export function modelWithInjectionContext<T = unknown>(injector: Injector): typeof model {
const modelFunction = (initialValue: T, opts?: ModelOptions): ModelSignal<T> =>
runInInjectionContext(injector, () => model(initialValue, opts));

modelFunction.required = (opts?: ModelOptions): ModelSignal<T> => runInInjectionContext(injector, () => model.required(opts));

return modelFunction as typeof model;
}

0 comments on commit 9f910d3

Please sign in to comment.