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

Custom search filter in ng-grid using a customized cellTemplate

I am facing an issue with the ng-grid search filter on a column that references a cellTemplate. In my data object, there are multiple fields. One of these fields is an array and I have used cellTemplate to create a div with ng-repeat in order to display t ...

What is the proper way to utilize a class with conditional export within the Angular app.module?

This query marks the initiation of the narrative for those seeking a deeper understanding. In an attempt to incorporate this class into app.module: import { Injectable } from '@angular/core'; import { KeycloakService } from 'keycloak-angul ...

What is the process for redirecting to an external URL while including post parameters?

When a user accesses my endpoint, I need it to automatically redirect them to an external URL with URL-encoded form parameters. Endpoint: https://example.com Form Parameters: Name: testing ID: 123456 I have attempted the following in Express. It succes ...

Ensuring validity with Vuelidate for customizable fields

There's a form where fields are dynamically added on a click event. I want a validation error to appear when the field value is less than 9 digits after changing or blurring it. The issue is that since the fields are created dynamically with the same ...

Utilizing React JS to Export Axios Response

I have an getAllUsers.js File that retrieves all users from the API. import axios from 'axios' export const fetchData = async () => { let response try { response = await axios.get('http://127.0.0.1:8000/api/users') } catc ...

Angular ngPaste not showing the latest values in my custom Directive

Check out this relevant jsFiddle example When I paste an item into the 'searchBar' text box within my directive, I am not receiving the updated value of the element text. Below is the code for my directive: app.directive('searchBar', ...

Alter and send back an object from within an asynchronous function

I'm struggling to access the updated fields of an object (userTracker) within asynchronous JavaScript code. Even after modifying the object inside a function (fetchUsers), it still returns as undefined. How can I successfully achieve this? This is wh ...

ReactJS encountered an error of type ERR_INVALID_ARG_TYPE

Hello there! I recently purchased a template from ThemeForest and everything was working perfectly with the previous version. However, upon updating to the new version, I encountered an error that looks like this: > TypeError [ERR_INVALID_ARG_TYPE]: Th ...

Problem arising from apostrophe usage in Javascript OData request

In my current project, I have a text input field that passes a value through JS to fetch filtered data of names from a JSON file using OData query parameters. However, I've encountered an issue where if a name contains an apostrophe, it results in a ...

Using React Refs to Trigger the video.play() Method - A Step-by-Step Guide

Is there a way to use a ref in order to trigger video.play()? Currently encountering an error: preview.bundle.js:261916 Uncaught TypeError: _this2.videoRef.play is not a function Take a look at my component: import React from 'react'; import s ...

Step-by-step guide on positioning an image to show at the bottom of a div

I am trying to create a div that covers 100% of the screen height, with a table at the top and white space below it for an image. However, when I add the image, it ends up directly under the table instead of at the bottom of the DIV. I have searched on G ...

What is the correct way to utilize "data:" in a jQuery AJAX call?

There seems to be an issue with my code within the deletePost function. The problem lies in the fact that $_GET['title'] is empty. Although I set the title value in the ajax using postTitle: $(this).siblings("h3.blog").text(), it doesn't see ...

Ways for enabling the user to choose the layout option

I am looking to develop a customized reporting system where users can select the specific fields they want to include in the report as well as arrange the layout of these fields. The data for the reports is sourced from a CSV file with numerous columns. Us ...

Guide on updating the form structure with ajax

Lately, I've been working on a contact module with 3 columns: name, email, and phone. There's also a +1 button that adds a new row to input another contact using ajax. However, a problem arises when updating the structure as the data in the old c ...

Angular 7 router navigate encountering a matching issue

I created a router module with the following configuration: RouterModule.forRoot([ {path: 'general', component: MapComponent}, {path: 'general/:id', component: MapComponent}, {path: '', component: LoginComponent} ]) Sub ...

Collect form input data containing a binary image and showcase it in a view using webapi

I am currently working on a webapi project using MVC architecture. The project involves converting a jpg image to binary data, sending it to a SQL server, and then retrieving the form data along with the image back as a jpg for display on the view. Althoug ...

When using Vue.js and Quasar to implement multiple filtering forms, an issue arises where the input value disappears

I am currently exploring how to implement multi-item filtering in Quasar, a framework of Vue. At the moment, I am utilizing input and checkbox elements. Everything seems to be functioning correctly, but there is an issue with the select item disappearing. ...

Can I apply a universal babel configuration across all of my personal projects?

It becomes tedious to duplicate the same configuration file for each new project I start. ...

Dealing with AJAX error in pure JavaScript

I have been attempting to address AJAX errors using the code below, but unfortunately, it does not seem to be effective. function ajaxPost(url, data, success, error) { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function () ...

Issues with routing in Node.js using Express

This is my first attempt at programming. I am currently in the process of setting up routing in the following way: var indexRouter = require('./routes/index'); var loginRouter = require('./routes/login'); app.use('/', indexRo ...