2

Have some 'status' elements on the page that I want to set delayed, meaning after a number of file uploads complete. Of course this is very easy with a jQuery selector, but how do I do this in the "Angular way"?

Here's the trick: the number of files uploading can be 1 to X, so these 'status' spans (to be filled with text after uploads complete) will each need to reference an item in an array.

I've tried a few things and I can't make it work.

Does my question make sense?

2 Answers 2

3

You can still use jQuery selectors in Angular the only real rule is you don't do DOM manipulation anywhere but custom directives. It's not entirely clear what you're trying to do but if you need to directly manipulate the DOM and can't achieve it with ng-class or ng-show/hide or some other built in directive then you probably need a custom directive.

Write them like

angular.module("myModule", []).directive("myAwesomeDirective", [function(){
    return {
       restrict:'E', //could be E = element, C = class, A = attribute
       scope: {incomingData:"="},
       link:function(scope,iElem,iAttrs) {
          //this function called for each instance of the directive
          //do your DOM manipulation here
           scope.$watch(function() {return scope.incomingData}, function(newVal,oldVal) {
              console.log(newVal);
          }, true)
       }
    }
}]).controller("MyCtrl", ["$scope", function($scope) {
    $scope.someArray = [1,2,3,4];
    $scope.addElement = function() {
        $scope.someArray.push(Math.floor(10*Math.random()));
    }
}]);

Usage like

<div ng-app="myModule" ng-controller="MyCtrl">
    <button ng-click="addElement()">Add random</button>
    test
    {{someArray}}
    <my-awesome-directive incoming-data="someArray"></my-awesome-directive>
</div>

See more here: http://docs.angularjs.org/guide/directive or http://www.egghead.io

If this doesn't help try showing some code or just explain more about what you have tried and what isn't working as expected.

EDIT

Updated to include some stuff for binding to an incoming parameter, will try to setup a fiddle for it.

http://jsfiddle.net/uBaSa/1/

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

5 Comments

shaunhusain: Thanks for the reply! I really appreciate it. I definitely understand custom directives, but they are called and update the dom only once when the view loads. I need to update the dom on a delay, after a file upload completes. Is there some way to cause an element to be re-bound? Follow?
You can use a $timeout to do something on an interval if that's what you're going for. I think the general case is you create a directive and you bind the directive to some data using an "isolate scope" check out the egghead.io videos on that they're pretty good. Basically you can pass in the array and setup a watch within the link function so when the array changes it triggers a function call.
Also no problem I tend to forget to acknowledge the thanks lately, but don't mean to be rude, I'm learning as well and teaching tends to be one of the best ways for me to learn so hopefully I can help you out here.
I like to thank anyone who offers help and advice because I truly appreciate it. It's very kind for someone to stop what they're doing to help me. I hear what you're saying about teaching to learn. I couldn't agree more. Teaching forces you think things through very carefully. I was able to make this work using this in the $http.fileUpload promise success...
var selector = ".status-" + config.data.fileIdx; var elem = angular.element(document.querySelector(selector)); Of course this is "not the Angular way" since it manipulates the DOM from the controller. I'll checkout a "watch".
0

Here is my solution. To implement you will need to visit Github and download and install angular-file-upload.js. Thank you danialfarid for this great Angular file upload tool!

Here is my view html...

<div>
    <b>Select one or many files by holding [Ctrl] when clicking name:</b> 
    <br/>

    <input type="file" ng-file-select="onFileSelect($files)" multiple>
    <br/><br/>

    <b>Selected File(s):</b>
    <ol ng-bind-html-unsafe="filesSelected()"></ol>
    <br/>

</div>

Here is my (the relevant part) controller....

angular.module('myApp.controllers', [])
    .controller('PhotoCtrl', ['$scope','$http', function($scope,$http) {

        $scope.selectedFiles = [];

        $scope.onFileSelect = function ($files) {
            $scope.selectedFiles = $files;
            for (var i = 0; i < $files.length; i++) {
                var $file = $files[i]; 
                $http.uploadFile({
                    url: 'server/PhotoUpload.php',
                    data: {"fileIdx": i},
                    file: $file
                }).success(function (data, status, headers, config) {
                    var selector = ".status-" + config.data.fileIdx;
                    var elem = angular.element(document.querySelector(selector));
                    var status = "";
                    if (data.ok == "true") {
                        elem.addClass('bold green'); 
                        status = "[ OK ]";
                    } else {
                        elem.addClass('bold red');
                        status = "[ " + data.error + " ]";
                    }
                    elem.html("&nbsp;" + status);
                    // to fix IE not refreshing the model
                    if (!$scope.$$phase) $scope.$apply();
                });
            }
        };

        $scope.filesSelected = function() {
            var html = "";
            for (var x = 0; x < $scope.selectedFiles.length; x++) {
                var file = $scope.selectedFiles[x];
                status = '<span class="status-' + x + '"></span>';
                html += "<li><span>" + file.name + " / size: " + file.size + "B / type: " + file.type + "</span>" + status + "</li>";
            }
            return html;
        };
    }]);

I'm linking the controller in the routeprovider. Also note the line url: 'server/PhotoUpload.php'. You'll need to Google for a PHP (or you can use node.js if you know how, PHP was easier for me right now) script to actually receive the files uploaded and write them to disk.

Don't forget to put the bold, green and red classes in your css file.

The kinda neat trick in this is in the $http promise success code. It receives the status for each file upload and then sets a green/red status message next to each numbered selected file. It works pretty well. I'll probably do two enhancements soon: 1) Show status icons with the status text and... 2) I'm going upload the files as CouchDB attachments rather than write a disk folder. I'm starting on #2 right now!

And "yes" I do know that updating the DOM from the controller isn't the "Angular way", however there is no other way to do this delayed file upload status display. Not that I've figured out. Please correct me if I'm wrong ;-) If you can suggest any improvements I would be very happy if you posted them :-)

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.