1

So I have a directive that accepts a callback function as a parameter with some other options. Here is the directive:

.directive('csvReader', [function () {

    // Function to convert to JSON
    var convertToJSON = function (content) {

        // Declare our variables
        var lines = content.csv.split('\n'),
            headers = lines[0].split(content.separator),
            columnCount = lines[0].split(content.separator).length,
            results = [];

        // For each row
        for (var i = 1; i < lines.length; i++) {

            // Declare an object
            var obj = {};

            // Get our current line
            var line = lines[i].split(new RegExp(content.separator + '(?![^"]*"(?:(?:[^"]*"){2})*[^"]*$)'));

            // For each header
            for (var j = 0; j < headers.length; j++) {

                // Populate our object
                obj[headers[j]] = line[j];
            }

            // Push our object to our result array
            results.push(obj);
        }

        // Return our array
        return results;
    };

    return {
        restrict: 'A',
        scope: {
            results: '=',
            separator: '=',
            complete: '&'
        },
        link: function (scope, element, attrs) {

            // Create our data model
            var data = {
                csv: null,
                separator: scope.separator || ','
            };

            // When the file input changes
            element.on('change', function (e) {

                // Get our files
                var files = e.target.files;

                // If we have some files
                if (files && files.length) {

                    // Create our fileReader and get our file
                    var reader = new FileReader();
                    var file = (e.srcElement || e.target).files[0];

                    // Once the fileReader has loaded
                    reader.onload = function (e) {

                        // Get the contents of the reader
                        var contents = e.target.result;

                        // Set our contents to our data model
                        data.csv = contents;

                        // Apply to the scope
                        scope.$apply(function () {

                            // Our data after it has been converted to JSON
                            scope.results = convertToJSON(data);

                            // If we have a callback function
                            if (scope.complete) {

                                // Execute our callback
                                scope.complete(scope.results);
                            }
                        });
                    };

                    // Read our file contents
                    reader.readAsText(file);
                }
            });
        }
    };
}])

as you can see, when the CSV file has been converted to JSON the complete callback function is invoked. On my view I have some HTML which looks like this:

<div class="portlet light" ng-if="controller.results.length && !controller.import.error">
    <div class="portlet-title">

        <div class="caption caption-md">
            <span class="caption-subject font-green-haze bold uppercase">Collections to import</span>
        </div>

        <div class="inputs">
            <div class="portlet-input input-inline input-small">
                <div class="input-icon right">
                    <i class="icon-magnifier"></i>
                    <input type="text" class="form-control form-control-solid" placeholder="search..." ng-model="controller.filter">
                </div>
            </div>
        </div>

        <div class="actions">
            <div class="btn-group btn-group-devided" data-toggle="buttons">
                <label class="btn btn-transparent grey-salsa btn-circle btn-sm" ng-repeat="size in controller.pageSizes" ng-class="{ active: controller.pageSize === size }">
                    <input type="radio" name="options" class="toggle" ng-model="controller.pageSize" ng-change="controller.pageSize = size"> {{ size }}
                </label>
            </div>
        </div>

    </div>
    <div class="portlet-body">

        <table class="table table-hover table-light">
            <thead>
                <tr class="uppercase">
                    <th>
                        <a href="" ng-click="controller.predicate = 'reference'; controller.reverse = !controller.reverse">Reference</a>
                    </th>
                    <th>
                        <a href="" ng-click="controller.predicate = 'customerReference'; controller.reverse = !controller.reverse">Customer Reference</a>
                    </th>
                    <th>
                        <a href="" ng-click="controller.predicate = 'customerName'; controller.reverse = !controller.reverse">Name</a>
                    </th>
                    <th>
                        <a href="" ng-click="controller.predicate = 'customerBusinessName'; controller.reverse = !controller.reverse">Company</a>
                    </th>
                    <th>
                        <a href="" ng-click="controller.predicate = 'supplierName'; controller.reverse = !controller.reverse">Supplier</a>
                    </th>
                    <th>
                        <a href="" ng-click="controller.predicate = 'collectionCode'; controller.reverse = !controller.reverse">Code</a>
                    </th>
                    <th>
                        <a href="" ng-click="controller.predicate = 'status'; controller.reverse = !controller.reverse">Status</a>
                    </th>
                    <th>
                        <a href="" ng-click="controller.predicate = 'plannedCollectionDate'; controller.reverse = !controller.reverse">Date</a>
                    </th>
                </tr>
            </thead>
            <tbody>
                <tr dir-paginate="collection in controller.results | orderBy: controller.predicate:controller.reverse | filter: controller.filter | itemsPerPage : controller.pageSize">
                    <td>
                        {{ collection.reference }}
                    </td>
                    <td>
                        {{ collection.customerReference }}
                    </td>
                    <td>
                        {{ collection.customerName }}
                    </td>
                    <td>
                        {{ collection.customerBusinessName }}
                    </td>
                    <td>
                        {{ collection.supplierName }}
                    </td>
                    <td>
                        {{ collection.collectionCode }}
                    </td>
                    <td>
                        {{ collection.status }}
                    </td>
                    <td>
                        {{ collection.plannedCollectionDate }}
                    </td>
                </tr>
            </tbody>
        </table>

        <dir-pagination-controls></dir-pagination-controls>

        <div class="form-group">
            <button class="btn btn-primary" ng-click="controller.save()">Import</button>
            <button class="btn btn-default" ng-click="controller.cancel()">Cancel</button>
        </div>
    </div>
</div>

When I click "choose file" and select a CSV file, the HTML above populate and I can see my data. But the problem is I want to validate it before I display it, so I was trying to pass the data from the directive to my controller via a function (hence the complete function), but when I try to console.log out the data I always get null.

Here is my method:

// Used to validate the imported data
self.validateResults = function (results) {

    console.log(self.results); // returns undefined
    console.log(results); // returns undefined
    console.log(self); // shows the results data as an array in self.results
};

and the directive in the HTML looks like this:

 <input type="file" csv-reader results="controller.results" complete="controller.validateResults(results)" />

Can anyone explain to me what I am doing wrong?

1 Answer 1

1

When you invoke callback with results you need to pass it in object with the key results:

if (scope.complete) {
    // Execute our callback
    scope.complete({results: scope.results});
}

The key results in the object you pass to scope.complete corresponds to the name of the parameter defined in HTML complete="controller.validateResults(results)".

Sign up to request clarification or add additional context in comments.

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.