0

I'm newbie to js and this is my first question in stackoverflow as well. So any comment or act of downgrading is understandable.

This is the angular-js-flowchart project on github. This is another stackoverflow topic that teachs how to use factory as a data getter involving $http.

My need is to generate data for the chart by using an Angular factory that returns a $http function. The $http talks to a php service that retrieve data from database. I have tested the service using jsonlint and its working fine. The directory of service is checked, relatively to the html file.

I copied the "factory" code from another stackoverflow question and applied to app.js in the angularjs-flowchart Github project.

The problem is that the Chrome console keeps throwing an error that I can not understand. Data is not retrieved. The error on console is "TypeError: Cannot read property 'getData' of undefined"

This is the modified-by-me app.js:

//
// Define the 'app' module.
//
angular.module('app', ['flowChart', ])

//
// Simple service to create a prompt.
//
.factory('prompt', function () {

    /* Uncomment the following to test that the prompt service is working as expected.
    return function () {
        return "Test!";
    }
    */

    // Return the browsers prompt function.
    return prompt;
})

//
// Application controller.
//
.controller('AppCtrl', ['$scope', 'prompt', function AppCtrl ($scope, prompt, dataFactory) {

    //
    // Code for the delete key.
    //
    var deleteKeyCode = 46;

    //
    // Code for control key.
    //
    var ctrlKeyCode = 65;

    //
    // Set to true when the ctrl key is down.
    //
    var ctrlDown = false;

    //
    // Code for A key.
    //
    var aKeyCode = 17;

    //
    // Code for esc key.
    //
    var escKeyCode = 27;

    //
    // Selects the next node id.
    //
    var nextNodeID = 10;


    //
    // Event handler for key-down on the flowchart.
    //
    $scope.keyDown = function (evt) {

        if (evt.keyCode === ctrlKeyCode) {

            ctrlDown = true;
            evt.stopPropagation();
            evt.preventDefault();
        }
    };

    //
    // Event handler for key-up on the flowchart.
    //
    $scope.keyUp = function (evt) {

        if (evt.keyCode === deleteKeyCode) {
            //
            // Delete key.
            //
            $scope.chartViewModel.deleteSelected();
        }

        if (evt.keyCode == aKeyCode && ctrlDown) {
            // 
            // Ctrl + A
            //
            $scope.chartViewModel.selectAll();
        }

        if (evt.keyCode == escKeyCode) {
            // Escape.
            $scope.chartViewModel.deselectAll();
        }

        if (evt.keyCode === ctrlKeyCode) {
            ctrlDown = false;

            evt.stopPropagation();
            evt.preventDefault();
        }
    };

    //
    // Add a new node to the chart.
    //
    $scope.addNewNode = function () {

        var nodeName = prompt("Enter a task name:", "New Task");
        if (!nodeName) {
            return;
        }

        //
        // Template for a new node.
        //
        var newNodeDataModel = {
            name: nodeName,
            id: nextNodeID++,
            x: 0,
            y: 0,
            inputConnectors: [ 
                {
                    name: "Pre"
                }           
            ],
            outputConnectors: [ 
                {
                    name: "Sub"
                }           
            ],
        };

        $scope.chartViewModel.addNode(newNodeDataModel);
    };

    //
    // Add an input connector to selected nodes.
    //
    $scope.addNewInputConnector = function () {
        var connectorName = prompt("Enter a connector name:", "New connector");
        if (!connectorName) {
            return;
        }

        var selectedNodes = $scope.chartViewModel.getSelectedNodes();
        for (var i = 0; i < selectedNodes.length; ++i) {
            var node = selectedNodes[i];
            node.addInputConnector({
                name: connectorName,
            });
        }
    };

    //
    // Add an output connector to selected nodes.
    //
    $scope.addNewOutputConnector = function () {
        var connectorName = prompt("Enter a connector name:", "New connector");
        if (!connectorName) {
            return;
        }

        var selectedNodes = $scope.chartViewModel.getSelectedNodes();
        for (var i = 0; i < selectedNodes.length; ++i) {
            var node = selectedNodes[i];
            node.addOutputConnector({
                name: connectorName,
            });
        }
    };

    //
    // Delete selected nodes and connections.
    //
    $scope.deleteSelected = function () {

        $scope.chartViewModel.deleteSelected();
    };


    //
    // Setup the data-model for the chart.
    //
    var chartDataModel = {};
    var handleSuccess = function(data, status){
        chartDataModel = data;
        console.log(chartDataModel);
    };

    dataFactory.getData().success(handleSuccess);

    //
    // Create the view-model for the chart and attach to the scope.
    //
    $scope.chartViewModel = new flowchart.ChartViewModel(chartDataModel);
}])
.factory('dataFactory', function($http){
    return {
        getData : function(){
            return $http.post("chart-data-retrieve.php");
        }
    };

});

Basically, what i added but doesn't work is

// Setup the data-model for the chart.
//
var chartDataModel = {};
var handleSuccess = function(data, status){
    chartDataModel = data;
    console.log(chartDataModel);
};

dataFactory.getData().success(handleSuccess);

and

.factory('dataFactory', function($http){
    return {
        getData : function(){
            return $http.post("chart-data-retrieve.php");
        }
    };

});

Please help, thanks.

2 Answers 2

2

I tried to set the chartViewModel of the $scope directly inside the service call, so the variable chartDataModel becomes redundant. And it works.

// Create the view-model for the chart and attach to the scope.
//
myService.then(function(data) {
    $scope.chartViewModel = new flowchart.ChartViewModel(data);
});
Sign up to request clarification or add additional context in comments.

Comments

1

I tried to return a promise, not a $http from the factory. It works now. The controller can now use the service to retrieve data. However I still could not set the controller's variable to the data retrieved. The following is the code:

.factory('myService', function($http, $q) {
  //this runs the first time the service is injected
  //this creates the service
  var deferred = $q.defer();

  $http.get('chart-data-retrieve.php').then(function(resp) {
    deferred.resolve(resp.data);
  });

  return deferred.promise;
})

And the code inside controller:

var chartDataModel = {};
//get data from myService factory
myService.then(function(data) {
    alert(data);
    chartDataModel = data;
});

Currently, the alert() show me the data already. However, the variable chartDataModel is still unset.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.