What's the deal with Angular's factory pattern?

Is it possible to implement a true Factory pattern in JavaScript and Angular where there is no need to constantly provide the "typeName" parameter? The transition from C# to Java reference types with Angular has been quite challenging for me, and I would appreciate any guidance on achieving this.

(function () {

        'use strict';

        angular
            .module('blocks.object-cache');

        objectCache.$inject = ['CacheFactory', '$auth'];

        function objectCache(CacheFactory, $auth) {
            var _options = {
                maxAge: (60 * 60 * 1000),
                deleteOnExpire: 'passive',
                storageMode: 'localStorage'
            };

            var service = {
                setOptions: setOptions,
                getCache: getCache,
                // Other functions here...

        return service;
        // Function implementations follow here...
    }

    })();

Answer №1

I may not be a master of Angular, but what if we simply relocate the functions to establish a factory-like pattern? I haven't tested this out yet, but with just about two minutes of copying and pasting...

Edit: Eliminated the nested iterate functions.

(function () {

    'use strict';

    angular
        .module('blocks.object-cache')
        .service('ObjectCache', ObjectCache);

    ObjectCache.$inject = ['CacheFactory', '$auth'];

    function ObjectCache(CacheFactory, $auth) {

        var _options = {
            maxAge : (60 * 60 * 1000),
            deleteOnExpire : 'passive',
            storageMode : 'localStorage'
        };

        var factory = {
            getCache : getCache
        };

        return factory;
        ////////////////////////////

        function getCache(typeName, options) {

            options = options || {};
            options.maxAge = options.maxAge = _options.maxAge;
            options.deleteOnExpire = options.deleteOnExpire = _options.deleteOnExpire;
            options.storageMode = options.storageMode = _options.storageMode;

            typeName    = normalizeTypeName(typeName || 'objects');
            var userId  = getUserId() || 'public';
            var name    = userId + '_' + typeName;

            var service = {
                type    : typeName,
                user    : userId,
                name    : name,
                options : options,
                cache   : CacheFactory(name) || CacheFactory.createCache(name, options),
                clear   : function () {
                    this.cache.removeAll();
                },
                getAll  : function () {
                    var result = [];
                    var keys = this.cache.keys() || [];
                    for (var i = 0; i < keys.length; i += 1) {
                        result.push(this.cache(keys[i]));
                    }
                    return result;
                },
                getItems : function (ids) {
                    var result = [],
                        _ids   = [];
                    for (var i = 0; i < (ids || []).length; i += 1) {
                        var id = ids[i];
                        if (_ids.indexOf(id) < 0) {
                            _ids.push(id);
                            var item = this.cache.get(id);
                            if (item) { result.push(item); }
                        }
                    }
                    return result;
                },
                getItem  : function (id) {
                    var items = this.getItems([id]);
                    return (items.length > 0) ? items[0] : null;
                },
                putItem  : function (item, id, refresh) {
                    var existing = this.cache.get(id);
                    if (existing && !refresh) { return true; }
                    if (existing) { this.cache.remove(id); }
                    this.cache.put(item, id);
                    return (!!this.cache.get(id));
                },
                putItems : function (items, idField, refresh) {
                    var success = true;
                    for (var i = 0; i < (items || []).length; i += 1) {
                        var item = items[i];
                        var id   = item[idField];
                        if (typeof id != 'undefined') {
                            if (this.putItem(item, id, refresh)) { success = false; }
                        }
                    }
                    return success;
                },
                getItemsByKey : function (key, value, isCaseSensitive) {
                    var result = [];
                    (this.getAll() || []).forEach(function(item){
                        var itemValue = item[key];
                        if (typeof itemValue != 'undefined') {
                            if ((typeof value == 'string') && (typeof itemValue == 'string') && (!isCaseSensitive || value.toLowerCase() == itemValue.toLowerCase())) {
                                result.push(item);
                            } else if (((typeof value) == (typeof itemValue)) && (value == itemValue)) {
                                result.push(item);
                            } else {
                                // Other scenarios?
                            }
                        }
                    });
                    return result;
                },
                getItemByKeyFirst : function (key, value, isCaseSensitive) {
                    var items = this.getItemsByKey(key, value, isCaseSensitive) || [];
                    return (items.length > 0) ? items[0] : null;
                },
                getItemByKeySingle : function (key, value, isCaseSensitive) {
                    var items = this.getItemsByKey(key, value, isCaseSensitive) || [];
                    return (items.length === 0) ? items[0] : null;
                },
                removeItemsByKey : function (keyField, values, isCaseSensitive) {
                    var keysToRemove = [],
                        keys = this.cache.keys() || [];
                    for (var k = 0; k < keys.length; k += 1) {
                        var key     = keys[k];
                        var item    = this.cache.get(key);
                        var itemVal = item[keyField];
                        if (typeof itemVal != 'undefined') {
                            for (var v = 0; v < (values || []).length; v += 1) {
                                if ((typeof values[v] == 'string') && (typeof itemVal == 'string') && (!isCaseSensitive || values[v].toLowerCase() == itemVal.toLowerCase())) {
                                    keysToRemove.push(key);
                                    break;
                                } else if (((typeof values[v]) == (typeof itemVal)) && (values[v] == itemVal)) {
                                    keysToRemove.push(key);
                                    break;
                                } else {
                                    // Other scenarios?
                                }
                            }
                        }
                    }
                    var success = true;
                    for (var r = 0; r < keysToRemove.length; r += 1) {
                        this.cache.remove(keysToRemove[r]);
                        if (this.cache.get(keysToRemove[r])) { success = false; }
                    }
                    return success;
                },
                removeItemByKey : function (keyField, value, isCaseSensitive) {
                    return this.removeItemsByKey(keyField, [value], isCaseSensitive);
                },
                putItemsByKey : function(items, keyField, refresh, isCaseSensitive) {
                    if (!!refresh) {
                        var values  = _.map((items || []), keyField);
                        if (!this.removeItemsByKey(keyField, values, isCaseSensitive)) { return false; }
                    }
                    for (var i = 0; i < (items || []).length; i += 1) {
                        var id = items[i][keyField];
                        if (typeof id != 'undefined') {
                            this.cache.put(items[i], id);
                            if (!this.cache.get(id)) { return false; }
                        }
                    }
                    return true;
                },
                putItemByKey : function (item, keyField, refresh, isCaseSensitive) {
                    return this.putItemsByKey([item], keyField, refresh, isCaseSensitive);
                }
            };

            return service;
        }


        function getUserId () {
            return $auth.isAuthenticated() ? ($auth.getPayload().sub || 'unknown') : null;
        }
        function normalizeTypeName (typeName) {
            return typeName.split('.').join('-');
        }
    }

})();

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Managing Alert and Confirmation Pop-ups Using JavascriptExecutor in Selenium with GhostDriver

In my current project, I am facing a challenge. I am utilizing Selenium 2.42.2 along with the phantomjsDriver 1.1.0 in Eclipse using Java. It is crucial for my test to be able to identify and save messages from Alerts, Confirms, and possibly Prompts when a ...

What is the best way to implement React.memo or useMemo and ensure semantic guarantees?

According to the documentation provided for useMemo: While useMemo can improve performance, it should not be solely relied upon for semantic guarantees. React may choose to recalculate previously memoized values in the future, such as to free up memo ...

Troubleshoot: How to Fix the socket.io net::ERR_CONNECTION_TIMED_OUT

I am facing an issue with my website's real-time chat functionality. It works perfectly on localhost without any errors. However, when I try to run it on the server, I encounter the following error: http://my.domain:52398/socket.io/?EIO=3&transpo ...

How can you use JavaScript regex to verify that the last three characters in a string are

What method can be used to confirm that a string concludes with precisely three digits? accepted examples: Hey-12-Therexx-111 001 xxx-5x444 rejected examples: Hey-12-Therexx-1111 Hey-12-Therexx-11 Hey-12-Therexx 12 112x ...

Can someone please provide a reference to an online illustration of implementing TinyMCE with a print format similar to Microsoft Word

Are there any online resources demonstrating the use of TinyMCE with a print layout resembling Word, with visible page breaks? Alternatively, are there any other WYSIWYG editors with a built-in print layout feature available for open source use? ...

Exploring deeply nested arrays in objects to locate matching elements

In my current array, there are multiple objects, each containing an array property. The array within each object holds different genres associated with a movie. const films = [ { name: 'Ant-Man and the Wasp', genre: ['Action&apo ...

Find the variance between the initial time and the present time, as well as the final time and the current time

If a user logs in before the start time of a game, they will receive a message indicating that the game will start in 01h:10m:23s. If the user logs in after the start time but before the end time, they will see a message stating that the game closes in 0 ...

Using Javascript and JQuery to display the current date upon the initial page load, then preserving the date when navigating to different

When using Bootstrap's Datepicker, I encountered a scenario where I need the current page to load when a user first visits the page. However, if the user selects a different date and then navigates to another page, I want the Datepicker to retain the ...

Interactive font-awesome icons within an interactive dropdown menu

I am currently facing an issue with using two Fontawesome icons in a clickable dropdown menu. The dropdown menu does not toggle when I click on the icons directly; however, it works when I click on the padding around them. The example provided by W3schools ...

Troubleshooting issues when testing Angular services using Jasmine and Chutzpah

I've been facing some challenges while attempting to test my AngularJs services with Jasmine as I encounter various errors consistently. In an effort to troubleshoot, I decided to create a simple Sum service for testing purposes but unfortunately, the ...

Tips for creating high-definition images from canvas artwork at a large scale

I'm considering using three.js for my upcoming art project. My goal is to create graphics through code and then save them in high resolution, like 7000 x 7000 px or more, for printing purposes. While I have experience with Flash and vvvv for similar ...

Updating the state in React can be achieved by using the `

Upon obtaining a list of search results, each result is equipped with an onclick function. My goal is to exhibit the user-selected results on the screen by adding them to an array upon click: let selectedData = [] function addFunc(resultdata){ consol ...

Example of a chat server code using NodeJS

I'm looking to add a chat module to my web application. After searching on , I found several chat modules but none of them have clear examples on how to implement them in my project. Can someone share a tutorial that is based on existing NodeJS modul ...

What is the best way to add a new row to an existing CSV file using json2csv in Node.js?

I need to append a new row to an existing CSV file. If the CSV file already exists, I want to add the new row after the last existing row without adding a column header. Here is the code snippet that I have been using: var fields = ['total', &a ...

Error message appears when trying to render a shallow mock of a React.Component that extends MyInterface with any type

Encountering an Issue with Component Mocking When attempting to mock a component, I am receiving the following error message: "Conversion of type '{ props: { index: number; AssignmentTitle: string; AssignmentDescription: string; AssignmentUtilizedHou ...

Autocomplete feature seems to be functioning properly in the online demonstration, while it does not seem

I can see that the autocomplete feature is working in the example provided, but it's not functioning properly in my attempt. What could be causing this issue? <!doctype html> <html lang="en"> <head> <meta charset="utf-8> & ...

Refresh the data in an existing Highstock chart with JavaScript only

I'm currently updating a website and unfortunately, I do not have access to the original code. All I am able to do is append new code at the end of it. The existing code consists of a highstock chart with specific data attributes. Here is the snippet ...

Using Angular and Express for client authentication

As I dive into the world of developing a server-side application with node.js and express, I find myself familiarizing myself with authenticating users using passport and local/OAuth strategies. However, I am facing a challenge when it comes to authorizing ...

The method for transferring text box values to the next page using a hyperlink in JSP is as follows:

Is there a way to pass the values of a text box in a JSP through a hyperlink on the same page? I want to achieve this but am not sure how. ...

Navigating through pages in a server component using Next.js

I am currently working on a project that involves implementing pagination using the NextJS 13 server component without relying on the use client. The goal is to ensure that when a button is clicked, new entries are added to the screen in a sequential order ...