Utilize morris.js within an AngularJS directive to handle undefined data

Using the morris.js charts in my angular js app has been a great addition. I decided to convert it into a directive for better organization and functionality:
barchart.js:

angular.module('app_name').directive('barchart', function () {
    return {
        // necessary for element functionality
        restrict: 'AEC',
        template: '<div class=chart_div></div>',
        replace: true,
        // observing and manipulating the DOM
        link: function ($scope, element, attrs) {

            var data = $scope[attrs.data],
                xkey = $scope[attrs.xkey],
                ykeys = $scope[attrs.ykeys],
                labels = $scope[attrs.labels];

            Morris.Bar({
                element: element,
                data: data,
                xkey: xkey,
                ykeys: ykeys,
                labels: labels,
                hideHover: true,
                grid: false
            });

        }

    };

});

Later on, within my page.html, I implemented the directive like this:

<section class="graphs" ng-controller="ChartController">
<div class="graphs_box">
    <div class="graphs_box_title">My Orders</div>
    <div class="chart_bg">
        <div barchart xkey="xkey" ykeys="ykeys" labels="labels" data="MyData"></div>
    </div>
</div>

The issue arises when attempting to add data to the chart in 'ChartController' like so:

        getChartData = function () {
        $scope.xkey = 'X';
        $scope.ykeys = ['Y'];
        $scope.labels = ['Total Tasks', 'Out of Budget Tasks'];
        $scope.PlannedChart = [
          { range: 'A', total_tasks: 20 },
          { range: 'B', total_tasks: 35 },
          { range: 'C', total_tasks: 100 },
          { range: 'D', total_tasks: 50 }
        ];
    };

Everything works perfectly fine this way. However, when trying to load data from a database (in json format) like this:

    getChartData = function () {
        ChartsService.getCharts("orders").success(function (data) {
            $scope.xkey = 'X';
            $scope.ykeys = 'Y';
            $scope.labels = ['Total Tasks', 'Out of Budget Tasks'];
            $scope.OrdersChart = data.Val_Chart;

        });
    };

It doesn't seem to work as expected. Despite successfully fetching the data from the database (as confirmed during debugging), the code seems to first pass through barchart.js with 'undefined' data before reaching the service that retrieves the data.

Answer №1

It seems like the issue arises from the asynchronous nature of getCharts("orders") being called here. To resolve this, you would have to invoke setData(data) on the object returned by Morris.Bar(). For more information, refer to the Morris.js Documentation

I managed to fix it by consolidating all directive attributes into a single object and implementing it in the link function as follows:

link: function ($scope, element, attrs) {


            var params = $scope[attrs.params];
            angular.extend(params, {element: element});

            var graph = Morris.Line(params);


            var refresh = function(new_params) {
                graph.setData(new_params.data);
            }

            $scope.$watchCollection(attrs.params, refresh);

        }

The

$scope.$watchCollection(attrs.params,refresh);
method monitors changes in the params object on the scope, allowing you to update the data array once the asynchronous loading is complete. This ensures the graph is updated accordingly.

Here is the directive element used:

<barchart params="sentin_chart"></barchart> 

And this is the object defined in the controller:

$scope.sentin_chart = {};
$scope.sentin_chart.data = [];
$scope.sentin_chart.xkey = 'day';
$scope.sentin_chart.ykeys = ['sent_in'];
$scope.sentin_chart.labels = ['Sent in Stories'];

Simply update the data array inside this object to refresh the graph with new data

$scope.sentin_chart.data = %NEWDATAARRAY%

I hope this explanation clarifies any confusion.

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

Animate CSS Grid to dynamically fill the viewport on top of current grid elements

Please note that I am specifically seeking vanilla JS solutions, as jQuery is not compatible with this project I have a grid structure that is somewhat complex: body { margin: 0; height: 100vh; text-align: center; } .grid-container { ...

When the React application loads, loadingbar.js will be mounted initially. However, as the props or states are updated, the object

I recently made the switch from using progressbar.js to loadingBar.js in my React application for widget progress. Everything was working smoothly with progressbar.js, but once I switched to loadingBar.js, I encountered a strange issue. After the page load ...

Image Handpicked by JCrop User

Successfully implemented JCrop example code for selecting an area on an image with a preview and getting coordinates. However, the challenge lies in allowing users to select an image from their file system, display it in the browser, and perform the afore ...

Having issues with "return false" not functioning properly in jQuery ajax calls

I have been developing a registration form using jQuery ajax. Below is the code snippet I am working with: function validateData() { var email = jQuery("#email").val(); var username = jQuery("#username").val(); var emailReg = /^([\w-&bsol ...

React-dnd supporting multiple draggable and droppable elements

I am facing a challenge with making multiple elements draggable using react-dnd. I have an array of 4 fields that I would like to make draggable, but when I map through the array and give each element a className of 'element', they do not move as ...

Apply jQuery styling to new select box on page in order to maintain consistent styling throughout

I've encountered an issue with my jQuery select box styling. It appears to work perfectly on the initial page load, but when new content containing a select box is dynamically loaded onto the page, the styling doesn't get applied to it. Can anyo ...

When utilizing $state.go(), the resolve promise of a parent state is not executed by ui-router

My issue involves an abstract parent state containing a resolve promise that fetches information about the current user. This data is then injected into controllers of all child states. The problem arises when I try to navigate using $state.go('paren ...

retrieving information from an AngularJS $q promise

I'm currently working on a series of promises for sequential http GET requests. Imagine sending a cooking recipe to the server one step at a time, in order, just like following a recipe to bake a perfect pie. The final step will return the result; in ...

The Access-Control-Allow-Origin CORS header does not align with the null value on the Ajax request

Encountering the same issue in my browser Cross-Origin Request Blocked: The Same Origin Policy prevents access to the remote resource at http://abc-test123.com/login. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘(null)’). My ...

Tips for modifying the max length value in Angular

I'm just starting out with Angular and I'm trying to alter the maxlength property from 300 to 140 upon clicking a button. The buttons are generated using ng-repeat and only the first one should change the value to 140, while the others should rem ...

Why is the jQuery datepicker malfunctioning when nested within ng-repeat in AngularJS?

I am currently facing an issue with the jquery ui date picker in my AngularJS application. The date picker is functioning correctly outside of any ng-repeat loops, but it stops working when placed within one. <input type="text" class="form-control date ...

Updating user data when logged in on multiple browsers can be tricky. Here's how to make sure that

I am currently using the express-session middleware to store user sessions in a Mongo collection. What is the most effective way to update all user sessions when changes are made from one session? For instance, if a user updates their email in session A, ...

Tips on validating ASP.NET gridview textbox with javascript during the update process:

I've implemented a gridview on my aspx page: <asp:GridView ID="gvPhoneBook" runat="server" AutoGenerateColumns="false" ShowFooter="true" DataKeyNames="PhoneBookID" ShowHeaderWhenEmpty="true" OnRowCommand="gvPh ...

The latest version of Next.js, 11.1.0, does not support monitoring for code changes within the node

In the latest version of Nextjs (11.1.0), there seems to be an issue where code changes in the `node_modules` directory are not being watched, unlike in the previous version (10.2.1). While working on a project with Nextjs 11.1.0, I have tried explicitly ...

How to dynamically update the maximum y-axis value in Vue-Chart.js without having to completely re-render the entire

Currently, I am involved in a project that requires the implementation of various charts from the Vue-Chartjs library. One specific requirement is to dynamically change the maximum value on the Y-axis whenever users apply different filters. To achieve this ...

The function to focus on this.$refs[("p" + index)] element is not available

I need help transforming a div into an input box when clicked, allowing me to edit the post inside a loop. Here is the button found on the post: <a @click="setFocusEdit(index)" v-if="isAuthor(post)" href="#" >Edit Me</a> And here is the spec ...

"Step-by-step guide on uploading multiple images to a Node server and storing them in

Hey everyone! I'm currently working on a project using React and MongoDB. Users are required to register and login before accessing the app. Once logged in, they can input their name, number, and images through a form. However, I've encountered a ...

An issue arose when attempting to proxy to: localhost, at port 4200, for the API endpoint v1/generate

Currently, I am following a tutorial which guides me through the process of creating an application using Angular CLI, Node.js, and Express. A proxy is used to initiate the app, with the proxy configuration file looking like this: { "/api/*": { ...

Avoid mutating the prop directly and instead, utilize a data or computed property that is based on the value of the prop. The prop that is being mutated in this case is

Help me understand this issue that Vue is displaying, I am not sure what is going on. This is my progress element: <el-progress :percentage="percentCompleted" v-show="uploadingVideo"></el-progress> data() { return{ percentCompleted: 0 ...

The three.js raycaster is able to detect objects both in front of and behind the specific object I am trying to select

I am currently working on rendering a 3D model of a house using Three.js and encountering an issue with the raycaster in my code. The problem I'm facing is that it's selecting every object both behind and in front of the specific object I want to ...