Utilizing Angular Directives and Controllers for Improved Efficiency

I have developed a custom dropdown option selector which is functioning well. It includes functions to fetch data from a specified URL in order to populate a list.

However, the issue arises when I attempt to reuse this component in a different section of my application with a separate dataset. This results in duplication of data and multiple executions of the controller's functions.

My understanding is that there are two main problems at hand. Firstly, services act as singletons, meaning that when the function to populate data is executed, it simply appends the new data to the existing dataset due to the presence of only one instance of the service.

Secondly, controllers do possess instances, leading to the execution of functions in each instance, thereby causing repetition.

The simplest solution might be to duplicate the component and assign it a different name. While this may resolve the issue temporarily, it would result in creating multiple copies of the same component if reusability for multiple instances is desired, which is not ideal.

Coming from an object-oriented programming background in Java, I understand that I might be applying OOP techniques in a language that does not fully support them ;)

Therefore, I realize the necessity to rethink my approach, but I seem to have hit a barrier. What would be the best way to tackle this problem?

Below is a JSFiddle link to provide better insight into what I am encountering:


var app = angular.module('myApp',[]);

app.directive('mySelector', function () {
return {
 scope: {
      mydata: '='
    },
    restrict: 'EA',
    template:'<select ng-model="timePeriodSelection" ng-options="timePeriodOption.name for timePeriodOption in timePeriodOptions"><option value="">Choose time period</option></select>',
controller: function($scope, myService) {
    //$scope.name = 'Superhero';
    console.log('test',$scope.mydata);
    myService.setData($scope.mydata);
    $scope.timePeriodOptions = myService.getData();
  console.log('test2',myService.getData());
    }
 };
});

app.factory('myService', function() {
var _data=[];    
return {
    setData: function(value){
        for (var a=0;a<value.length;a++){
            _data.push(value[a]);
        }
    },
    getData: function(){
        return _data
    }            
}
});

https://jsfiddle.net/devonCream/ess9d6q6/

Unfortunately, I cannot share the actual code for confidentiality reasons. However, imagine that instead of passing in a hardcoded value, I am fetching data from a URL through a service and storing it in an array within the factory. With each execution, the data keeps accumulating! This code serves as a demonstration.

Answer №1

If you are looking to create a custom drop-down feature, it is recommended to implement it as a directive for better organization. There are various methods to achieve the desired functionality using a directive. You can refer to the directive walkthroughs for additional guidance.

It is advisable to incorporate an isolate scope, utilize a template, and include a link function in your directive implementation.

One approach involves having preset items:

angular.module('myApp')
    .directive('myDropdown', function () {
        return {

            scope: {},

            template: '' +
                '<div class="my-dropdown">' +
                    '<div class="my-dropdown-item" ng-repeat="item in items">{{item.text}}</div>' +
                '</div>',

            link: function (scope, element, attrs) {
                scope.items = ['Item 1', 'Item 2', 'Item 3'];
            }

        };
    });

Alternatively, you can pass the items dynamically to each instance:

angular.module('myApp')
    .directive('myDropdown', function () {
        return {

            scope: {
                items: '='
            },

            template: '' +
                '<div class="my-dropdown">' +
                    '<div class="my-dropdown-item" ng-repeat="item in items">{{item.text}}</div>' +
                '</div>'

        };
    });

--UPDATE--

Here is an example where data is fetched once from a service:

angular.module('myApp')
    .service('dataService', function ($http) {
        var items;

        $http.get('http://ab.com/dropdown-items')
        .then(function (res) {
            items = res.data;
        });

        return {
            items: items
        };
    })
    .directive('myDropdown', function (dataService) {
        return {

            scope: {},

            template: '' +
                '<div class="my-dropdown">' +
                    '<div class="my-dropdown-item" ng-repeat="item in items">{{item.text}}</div>' +
                '</div>',

            link: function (scope, element, attrs) {
                scope.items = dataService.items;
            }

        };
    });

Answer №2

After much contemplation, I have come to the conclusion that the most effective solution to this issue is to store the data in the controller itself. This approach ensures that the data remains isolated within its own controller instance, preventing any potential conflicts.

In my revised 'fiddle', I have demonstrated how utilizing two different data sources (represented by two factories acting as models) can bring the data back into the controller for processing and storage.

Typically, if I were not reusing the component, I would integrate this logic into the factory. However, doing so only leads me back to the initial problem I encountered.

Furthermore, in my actual project, I perform checks on variables to determine which 'instance' has been triggered, allowing me to call methods accordingly. Although this process may seem cumbersome, it appears to be the most reliable approach until Angular 2 resolves these issues.

Here is the link to my updated jsfiddle

    var app = angular.module('myApp',[]);

app.directive('mySelector', function () {
return { 
    scope: true,
    bindToController:  {
        mydata: '@mydata',     
        timePeriodOptions: '='
    },
    controllerAs: 'selCtrl',
    restrict: 'EA',
    template:'<select ng-model="timePeriodSelection" ng-options="timePeriodOption.name for timePeriodOption in selCtrl.timePeriodOptions"><option value="">Choose time period</option></select>',
    controller: 'selCtrl'
 };
});    
app.controller('selCtrl', function($scope, myService) {
    var selCtrl = this;    
    selCtrl.timePeriodOptions = [];
    if (angular.isString(selCtrl.mydata)){
        processData();
    }
    function processData(){
        var value = myService.getData(selCtrl.mydata);
        for (var a=0;a<value.length;a++){
            selCtrl.timePeriodOptions.push(value[a]);
        }
    };
});

app.factory('myService', function(dataModel1,dataModel2) {
return {
    getData: function(model){
        var _data = []        
        if (model === "1"){
            _data = dataModel1.getData();
        }else{
            _data = dataModel2.getData();
        }
        console.log('data ',_data);
        return _data
    }            
    }
});
app.factory('dataModel1', function() {
    var _data=[{"name":1,"value":1},{"name":2,"value":2},{"name":3,"value":3}];    
    return {
        getData: function(){
            return _data
        }            
    }
});
app.factory('dataModel2', function() {
    var _data=[{"name":4,"value":4},{"name":5,"value":5},{"name":6,"value":6}];    
    return {
        getData: function(){
            return _data
        }            
    }
});

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

The sorting feature for isotopes is malfunctioning following the addition of a new div element

Isotope was utilized for sorting divs based on attribute values, however, a problem arises when a new div is added or an existing div is edited. The sorting functionality does not work properly in such cases, as the newly created or edited div is placed at ...

The issue arises when d3.scaleLinear returns NaN upon the second invocation

My journey with d3.js is just beginning and I'm taking it slow. Currently, I'm focused on creating a bar chart where data is loaded from a json file. When I click on the bars, the data changes to another column in the json. This is how my json f ...

Refreshing a <div> element in Django, yet there is no visible update

As I utilize a barcode scanner to add objects to my array list, the data is populated after each scan depending on the scanning speed of the user. To exhibit this data, I have designed a dedicated page. My intention is to avoid refreshing the entire page b ...

Having trouble getting the npm package with @emotion/react and vite to function properly

Encountering an issue with the npm package dependencies after publishing, specifically with @emotion/react. This problem arose while using vite for packaging. Upon installing the package in another project, the css property appears as css="[object Ob ...

Comparing the map function and for loop in the Puppeteer package for Node.js

I experimented with the Puppeteer package in NodeJS and noticed a significant difference in functionality between using the map function versus a for loop. Here is an illustration of what I observed: Using the map function: data.map(async(info) =>{ ...

Incorporating a static background image slideshow in ASP.NET - a step-by-step guide

I am currently working on my asp.net website and I would like to incorporate an image slideshow as the background of my homepage. This idea was inspired by a site I came across, . I have successfully implemented the slideshow, but now I am wondering if it ...

Combining JSON objects to form a new object within a JSON object using JavaScript

Here is the JSON data that I have: {"rows":[ {"shiftId":1,"shift":"Morning","item":"Tea","value":20}, {"shiftId":1,"shift":"Morning","item":"Coffee","value":30}, {"shiftId":2,"shift":"Evening","item":"Tea","value":40}, {"shiftId":2,"shift" ...

Interacting with PHP Session Objects

Can you offer me some advice? I'm having trouble with session/object interactions... <?php class ShoppingCart { public $products public function __construct($session) { $this->products = $session['products']; ...

Tips on keeping a div element in a fixed position until triggered by jQuery

I've managed to create a navigation bar within a header that sticks to the top of the screen once you scroll down past 100px. The functionality works well, but I'm looking to make the navigation bar stay fixed on the right until it snaps, essenti ...

Enhance CKEditor with Linked Select Boxes Plugin

I have ventured into writing a CKEditor Plugin and have grasped the basic concepts. For instance: CKEDITOR.dialog.add( 'addDocumentGroupDialog', function ( editor ) { return { title: 'Link to a document group', min ...

Creating dropdown options with JSON and Angular

This dilemma has been causing me no end of distress. I am trying to figure out how to populate options for a select tag from a JSON object using Angular. Here is a snippet of the code: <select id="cargo" ng-model="cargo.values.cargoList"> <op ...

Is it possible to retrieve a variable from a geojson file using Vue 3 and Vite?

For my Vue 3 project, I am trying to import a variable from a geojson file. However, when I use import line from '@static/line.geojson', my page goes blank and it seems like Vue stops working. If I use import line from '@static/line.json&ap ...

Node.js: Promise chain abruptly stops after reaching a predefined limit without causing any errors

Currently, I am attempting to perform a straightforward operation in nodejs using promises. My task involves working with an array that consists of objects. These objects contain query parameters for a URL that I need to access through a GET request. As th ...

When Selenium in JavaScript cannot locate a button element, use `console.log("text")` instead

I am trying to capture the error when there is no button element available by using console.log("No element"). However, my code is not working as expected. const {Builder, By} = require("selenium-webdriver"); let driver = new Builder().forBrowser("chrome ...

Steps for creating a PDF file from an HTML page using JavaScript coding

I'm developing an HTML5 hybrid iPad app and need to create a PDF file of a report generated on one of the pages. I would like to save this PDF on the iPad. Can you provide assistance with achieving this task? I am utilizing JavaScript and mobile jQuer ...

Triggering multiple functions by clicking on the Icon

I'm trying to execute two different functions when the user clicks on the Icon, but I keep getting an error that says: Expected onClick listener to be a function, instead got a value of object type. Can someone please help me figure out what I am doin ...

JavaScript array with more than 4 elements

I am working on a program where I have created an array and now want to display all the words that contain more than 4 letters. Check out my code snippet below: function oppC(){ var ord = ["Apple", "Two", "Yesterday", "mother", "lol", "car", "co ...

The process of executing a PHP file from JavaScript using XMLHttpRequest is experiencing issues on a XAMPP local server

I'm attempting to execute a PHP file using JavaScript. I have my XAMPP server set up and all files saved in the htdocs folder. The PHP file is also stored in the htdocs folder and works correctly when accessed via http://localhost/php_test.php in Chro ...

Is there a way for me to manually designate certain domains with the rel="follow" attribute while assigning all other external links with the rel="nofollow" attribute?

I'm working on developing a community platform similar to a social network. I've implemented a code that automatically makes all external links nofollow. However, I would like to create a feature that allows me to remove the nofollow attribute f ...

I encountered an error while using the router: TypeError: Cannot read property 'use' of undefined

Hello everyone, I am new to node.js and seeking help from experts. I am currently working on a code for user synchronization using node.js + AWS Cognito + Facebook Login. I followed an example from this link. Everything was going smoothly until I reached ...