ProductPromotion
Logo

Angular.JS

made by https://0x3d.site

GitHub - zuriscript/signalstory: Signal-based state management for Angular applications
Signal-based state management for Angular applications  - GitHub - zuriscript/signalstory: Signal-based state management for Angular applications
Visit Site

GitHub - zuriscript/signalstory: Signal-based state management for Angular applications

GitHub - zuriscript/signalstory: Signal-based state management for Angular applications

License: MIT npm version Commitizen friendly PRs coc-badge styled with prettier

signalstory is a state management library based on angular signals. It offers a range of architectural options, from simple repository-based state management (signal-in-a-service) to orchestrating decoupled commands, handling side effects through encapsulated objects, and facilitating inter-store communication using an event-driven approach. The ultimate goal is to provide a great user experience for all developers, whether junior or senior, while incorporating all the features you need to master your frontend state requirements.

[!TIP]
Starting out? You can keep it nice and simple if you prefer to avoid exploring all the advanced features that a state management library can offer! Begin by checking out the store, and only dive into the rest if you're curious later on.

Here's a snapshot of some notable highlights:

✅  Signal-in-a-service approach
✅  Simple, non-intrusive and lightweight
✅  Optimized for Scalability
✅  Imperative-first with Declaritive capabilities
✅  Immutability on demand
✅  Rich plugin ecosystem
✅  Native IndexedDB support
✅  Transactional Undo/Redo
✅  Global State Snaphots and Rollbacks
✅  Devtools support
✅  Effect and Store status tracking
✅  Realtime store performance statistics
✅  Custom plugin support
✅  Built-in testing utilities
✅  SSR friendly
✅  Tree-shakeable

Let the store grow with your project

Guiding Principles

  • 🚀 Use class methods to provide controlled access and mutations to shared state.
  • 🌌 If your store becomes too complex and bloated, slice it into multiple stores.
  • ✨ Join and aggregate your state at the component level using signal mechanics.
  • 🌐 Need to sync states between stores synchronously? - Use events.
  • 🔮 Need to decouple actors and consumers as you do in redux? - Use events.
  • 🔄 Craving Immutability? - Just activate it.
  • 🏎️ Don't want full immutability because your store has to be super fast? - Don't activate it.
  • 🧙‍♂️ Seeking a way to encapsulate side effects in a reusable, maintainable, and testable way? - Use effect objects.
  • 🔍 Want a way to reuse and test queries spanning over multiple stores? - Use query objects.
  • 📦 Don't want to use a class for stores? - You don't have to.
  • 🛠️ Tired of debugging state changes in the console? - Enable redux devtools.
  • 🪄 Still want some good old logging magic? - Enable Store logger plugin
  • ⏳ Need to keep track of store history and perform undo/redo operations? - track the history.
  • 💾 Want to sync your state with local storage? - Enable the persistence plugin.
  • 🗄️ Need a more sophisticated store storage or building an offline app? - Use IndexedDB adapter
  • 📈 Need to get notified of whether your store is modified or currently loading? - Enable the Store Status plugin.
  • 📊 Wondering where your bottlenecks are? - Enable the performance counter plugin
  • 🎨 Something's missing? - Write a custom plugin.
  • 📖 Read the docs for more features and concepts.

Installation

Install the library using npm:

npm install signalstory

Sneak peek

import { produce } from 'immer';

// Immutable store class using immer.js for boosting immutable mutations
@Injectable({ providedIn: 'root' })
class BookStore extends ImmutableStore<Book[]> {
  constructor() {
    super({
        initialState: { ... },
        name: 'Books Store',
        mutationProducerFn: produce,
        plugins: [
          useDevtools(),
          usePerformanceCounter(),
          useLogger(),
          useStoreStatus(),
          useStorePersistence(
            configureIndexedDb({
              dbName: 'SharedDatabase',
          })),
        ],
    });
    
    // Handle store reset request events. Note, the storeResetRequestEvent would 
    // be created or imported, see the events documentation for more details
    this.registerHandler(storeResetRequestEvent, store => {
      store.set([], 'Reset');
    });
  }

  // Query
  public get getBooksInCollection() {
    return computed(() => this.state().filter(x => x.isInCollection));
  }

  // Command
  public addToCollection(bookId: string) {
    this.mutate(state => {
      const book = state.find(x => x.id === bookId);
      if (book) {
        book.isInCollection = true;
      }
    }, 'Add Book To Collection');
  }
}
// Encapsulated multi store query object
export const BooksAndPublishersByAuthorInSwitzerlandQuery = createQuery(
  [BookStore, PublisherStore],
  (books, publishers, authorId: string) => {
    const booksFromAuthor = books.state().filter(x => x.author === authorId);
    const publishersInSwitzerland = publishers
      .state()
      .filter(x => x.country === 'CH');

    return booksFromAuthor.map(book => ({
      book,
      publisher: publishersInSwitzerland.find(
        p => p.id === book.mainPublisherId
      ),
    }));
  }
);
// And then run it
const query = myBookStore.runQuery(
  BooksAndPublishersByAuthorInSwitzerlandQuery,
  'sapowski'
);
// Encapsulated effect object
export const fetchBooksEffect = createEffect(
  'Fetch Books',
  (store: BookStore) => {
    const service = inject(BooksService);
    const notification = inject(NotificationService);

    return service.fetchBooks().pipe(
      catchError(err => {
        notification.alertError(err);
        return of([]);
      }),
      tap(result => store.setBooks(result))
    );
  },
  {
    setLoadingStatus: true, // indicates that the store is loading while the effect runs
    setInitializedStatus: true, // it should mark the store as initialized upon completion
  }
);
// And then run it
myBookStore.runEffect(fetchBooksEffect).subscribe();
const loadingSignal = isLoading(myBookStore); // true while effect is running
const initializedSignal = initialized(myBookStore); // true after initializing effect completion
const modifiedSignal = modified(myBookStore); // true after store update
// Track history spanning multiple stores
const tracker = trackHistory(50, store1, store2);

// Undo single commands
store1.set({ value: 10 }, 'ChangeCommand');
tracker.undo();

tracker.beginTransaction('Transaction Label');
store1.set({ value: 42 }, 'ChangeCommand');
store2.set({ value: 23 }, 'AnotherCommand');
tracker.endTransaction();

// Undo both commands on store1 and store2 at once
tracker.undo();

// Redo the whole transaction
tracker.redo();

Sample Application

To set up and run the sample app locally, follow the steps below:

  1. Clone the repository: Clone the repository containing the signalstory library and the sample app.

  2. Install dependencies: Navigate to the root directory of the repository and run the following command to install the necessary dependencies:

    npm install
    
  3. Build the library: Run the following command to build the signalstory library:

    ng build signalstory
    
  4. Serve the sample app: Run the following command to serve the sample app locally:

    ng serve sample --open
    

More Resources
to explore the angular.

mail [email protected] to add your project or resources here 🔥.

Related Articles
to learn about angular.

FAQ's
to learn more about Angular JS.

mail [email protected] to add more queries here 🔍.

More Sites
to check out once you're finished browsing here.

0x3d
https://www.0x3d.site/
0x3d is designed for aggregating information.
NodeJS
https://nodejs.0x3d.site/
NodeJS Online Directory
Cross Platform
https://cross-platform.0x3d.site/
Cross Platform Online Directory
Open Source
https://open-source.0x3d.site/
Open Source Online Directory
Analytics
https://analytics.0x3d.site/
Analytics Online Directory
JavaScript
https://javascript.0x3d.site/
JavaScript Online Directory
GoLang
https://golang.0x3d.site/
GoLang Online Directory
Python
https://python.0x3d.site/
Python Online Directory
Swift
https://swift.0x3d.site/
Swift Online Directory
Rust
https://rust.0x3d.site/
Rust Online Directory
Scala
https://scala.0x3d.site/
Scala Online Directory
Ruby
https://ruby.0x3d.site/
Ruby Online Directory
Clojure
https://clojure.0x3d.site/
Clojure Online Directory
Elixir
https://elixir.0x3d.site/
Elixir Online Directory
Elm
https://elm.0x3d.site/
Elm Online Directory
Lua
https://lua.0x3d.site/
Lua Online Directory
C Programming
https://c-programming.0x3d.site/
C Programming Online Directory
C++ Programming
https://cpp-programming.0x3d.site/
C++ Programming Online Directory
R Programming
https://r-programming.0x3d.site/
R Programming Online Directory
Perl
https://perl.0x3d.site/
Perl Online Directory
Java
https://java.0x3d.site/
Java Online Directory
Kotlin
https://kotlin.0x3d.site/
Kotlin Online Directory
PHP
https://php.0x3d.site/
PHP Online Directory
React JS
https://react.0x3d.site/
React JS Online Directory
Angular
https://angular.0x3d.site/
Angular JS Online Directory