Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Nik 1144 posts 4732 karma points MVP 2x c-trib
    Apr 18, 2019 @ 14:08
    Nik
    0

    Content App with File Upload ability

    Hey All,

    So I've been asking a few people around Twitter and Slack and I've manged to get so far with their wonderful help but I think I'm missing something.

    I've created a content app, but part of the requirement for it is that editors can use it to upload data which is then stored into a custom DB table. The Content app is for view this data as is directly relates to this specific page type.

    In my content app index.html I have the following:

    <div class="club-import" style="position:relative;">
        <div class="umb-pane">
            <div name="uploadClubData">
                 <umb-load-indicator ng-show="vm.isUploading"></umb-load-indicator>
                 <div ng-show="!vm.isUploading">
                     <umb-control-group label="Select the files to upload" hide-label="false" class="filename-field">
                         <umb-single-file-upload rebuild="rebuildInput"></umb-single-file-upload>
                     </umb-control-group>
                     <div class="alert alert-danger" ng-show="vm.fileError">
                            Invalid file extension. Only files with the extension .json are allowed.
                     </div>
                     <button type="button" ng-click="vm.upload()" data-element="toureditor-uploadfile" class="btn btn-primary" ng-disabled="!vm.canUpload">Upload</button>
                  </div>
              </div>
           </div>
        </div>
    

    Which is a replication of code from Dave Woestenborghs wonderful Tours Editor ( https://github.com/dawoe/umbraco-tour-editor/blob/develop/Source/Our.Umbraco.TourEditor/Web/App_Plugins/TourEditor/backoffice/toureditor/upload.html )

    In my controller I have the following:

    function myController($scope, notificationsService, importerResource) {
        var vm = this;
    
        function init(){
             vm.canUpload = false;
             vm.fileError = false;
             vm.isUploading = false;
             vm.upload = upload;
    
             //listen for when a file is selected
            $scope.$on("filesSelected", function (event, args) {
                vm.canUpload = false;
                if (args.files.length <= 0 || $scope.processing) {
                    vm.file = null;
                    return;
                }
                $scope.noFile = false;
                var file = args.files[0];
                var extension = file.name.substring(file.name.lastIndexOf(".") + 1, file.name.length).toLowerCase();
                if (extension !== "csv") {
                    $scope.invalidFileFormat = true;
    
                    $timeout(function () {
                        $scope.rebuildInput += 1;
                        vm.file = null;
                        $scope.invalidFileFormat = false;
                    }, 1000);
                    return;
                }
                vm.canUpload = true;
                vm.file = file;
            });
        }
    
        function upload(e) {             
            if (vm.file !== undefined) {
                vm.isUploading = true;            
                importerResource.uploadData(vm.file).then(
                    function (data) {
                        notificationsService.success('File uploaded succesfully');
                        vm.isUploading = false;
                    },
                    function (err) {                        
                        notificationsService.showNotification(err.data.notifications[0]);
                        vm.isUploading = false;
    
                    });
            }
        }        
    
        init();
    }
    

    And then I have a resource that looks as follows:

     function clubImporterResource($http, umbRequestHelper) {
        var apiUrl = Umbraco.Sys.ServerVariables["ClubData"]["DataApiUrl"];
        var resource = {
            uploadData: uploadData
        };
    
        return resource;
    
        function uploadData(file) {
            return umbRequestHelper.resourcePromise(
                $http({
                    method: 'POST',
                    url: apiUrl + "UploadClubData",
                    // If using Angular version <1.3, use Content-Type: false.
                    // Otherwise, use Content-Type: undefined,
                    data: file,
                    transformRequest: function (data) {
                        var formData = new FormData();
                        formData.append('file', data, data.name);
                        return formData;
                    },
                    headers: { 'Content-Type': undefined }
                }),
                "Failed uploading Club Data"
            );
        }
    
    }
    

    The idea being that this is uploaded to a custom API end point.

    So there are 2 strange things happening.

    1) After the "filesSelected" event triggers and runs, the input control looses the name of the file. Having stepped through the code, it appears to be there after my handler for filesSelected finished running but after it finished propagating up it suddenly disappears (no idea why)

    2) When I hit the "transformRequest" method in the resource it is throwing a "Illegal invocation" error which I don't understand.


    Following on from this, I've also tried replacing my upload method in my controller to us the same code here: https://t.co/3YjpdMAQjG

    This has gotten me able to upload files to my API controller (solving question 2) .. however I still have weird behaviour for question 1....

    Anyone got any ideas?

    Nik

  • Kevin Jump 1525 posts 9754 karma points MVP 3x c-trib
    Apr 18, 2019 @ 14:24
    Kevin Jump
    0

    Hi Nik,

    this is the same issue i ran into yesterday :(

    the data passed to transformRequest, looses the File element between calls - i think this may be something that has changed in Angular, between v7 and v8 of umbraco.

    i did find something in the Angular Docs

    Note: AngularJS does not make a copy of the data parameter before it is passed into the transformRequest pipeline. That means changes to the properties of data are not local to the transform function (since Javascript passes objects by reference). For example, when calling $http.get(url, $scope.myObject), modifications to the object's properties in a transformRequest function will be reflected on the scope and in any templates where the object is data-bound. To prevent this, transform functions should have no side-effects. If you need to modify properties, it is recommended to make a copy of the data, or create new object to return.

    Which may indicate why it is going - just not sure how to keep it!

    In the end I used the Upload service (included in umbraco 8) directly

    so i have the following html

            <umb-control-group label="File"
                               description="File to upload">
                <input type="file"
                       accept=".xml,.xliff,.xlf"
                       ng-model="pvm.files" 
                       umb-file-upload 
                       ngf-select
                       ngf-multiple="false"/>
    
                <umb-button action="pvm.uploadFile()"
                            type="button"
                            button-style="info"
                            state="vm.buttonState"
                            label-key="translate_upload">
    
                </umb-button>
            </umb-control-group>
    

    and then in my javascript i have - something like this (its not exactly this, i have a controller/service separation)

     // code to get the stuff from the model -
    
    Upload.upload({
      url: 'path to my upload api call',
      fields: {
          'jobId': jobId
       },
       file: file
    }).then(.... code to handle the returns...) ;
    

    .

Please Sign in or register to post replies

Write your reply to:

Draft