Skip to content

Commit

Permalink
updated 3.0 - refactored to use angularjs directive for submit control
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom Wilson committed Mar 11, 2013
1 parent 0e32a4a commit 9988098
Show file tree
Hide file tree
Showing 10 changed files with 381 additions and 215 deletions.
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# 0.3.0

* Refactored API

Now there are two directives, ng-upload on your upload form and
upload-submit on your clickable submit object. This new pattern
is more angularjs like and you can declare these directives as
attributes or classes.

see the examples


# 0.2.1

* Added test
* Modified callback function to use angularjs $parse
* Removed explict usage of $ as jQuery

# 0.2.0

* Bug fixes and enahncements (#12 and #13)
* Addition of an example to demonstrate using ngUpload to submit a full form, with a file input and other types of inputs, to the server.
* Example also demonstate how to consume a JSON returned by the server in Angular. (Checkout example 5 on the demo page(s) - [ASP.Net MVC](http://ng-upload.azurewebsites.net) or [NodeJS](http://ng-upload.eu01.aws.af.cm/).

## Update 0.1.1

* ngUpload is now an AngularJS Directive, removing the need to deal with the form[@id] attribute.
* Addition of the __uploadOptionsEnableControls__ option to prevent the default disabling of submission controls during upload, like so:
``` html
<form ng-upload='callbackFunction(contents, completed)' uploadOptionsEnableControls>
...
</form>
```
_Submission controls are html elements marked with the **upload-submit** css class_.
* Some bug fixes.


This source code of this example is given below:
4 changes: 2 additions & 2 deletions examples/nodejs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ <h1>Example 1 - Running with default configuration (requirement: v0.1.1 and abov
<span>Current value of foo is: <b>{{foo}}</b>. <i>(Works with the active $scope.)</i></span>
<br />
<br />
<form ng-upload="bar(content)" method="POST" action="/upload?delay=yes">
<form ng-upload method="POST" action="/upload?delay=yes">
<p>
<label>Select a file to upload:</label>
<input type="file" name="file" />
</p>
<p>
<input type="submit" class="btn upload-submit" value="Submit" />
<input upload-submit="bar(content)" type="submit" class="btn" value="Submit" />
<br />
<i>Button is <b>disabled</b> during upload, by default. (See Example 2 to change this).</i>
</p>
Expand Down
152 changes: 73 additions & 79 deletions examples/nodejs/libs/js/ng-upload.js
Original file line number Diff line number Diff line change
@@ -1,112 +1,106 @@
// Version 0.2.0
// Version 0.3.0
// AngularJS simple file upload directive
// this directive uses an iframe as a target
// to enable the uploading of files without
// losing focus in the ng-app.
//
// <div ng-app="app">
// <div ng-controller="mainCtrl">
// <form action="/uploads" ng-upload="results()">
// <form action="/uploads" ng-upload>
// <input type="file" name="avatar"></input>
// <input type="submit" value="Upload"></input>
// <input type="submit" value="Upload"
// upload-submit="submited(content, completed)"></input>
// </form>
// </div>
// </div>
//
// angular.module('app', ['ngUpload'])
// .controller('mainCtrl', function($scope) {
// $scope.results = function(content) {
// console.log(content);
// $scope.submited = function(content, completed) {
// if (completed) {
// console.log(content);
// }
// }
// });
//
angular.module('ngUpload', [])
.directive('ngUpload', ['$parse', function ($parse) {
.directive('uploadSubmit', ['$parse', function($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {

restrict: 'AC',
link: function(scope, element, attrs) {
// Options (just 1 for now)
// Each option should be prefixed with 'upload-Options-' or 'uploadOptions'
// Each option should be prefixed with 'upload-options-' or 'uploadOptions'
// {
// // specify whether to enable the submit button when uploading forms
// enableControls: bool
// }
var options = {};
options.enableControls = attrs.uploadOptionsEnableControls;

// get scope function to execute on successful form upload
if (attrs.ngUpload) {

element.attr("target", "upload_iframe");
element.attr("method", "post");

// Append a timestamp field to the url to prevent browser caching results
element.attr("action", element.attr("action") + "?_t=" + new Date().getTime());

element.attr("enctype", "multipart/form-data");
element.attr("encoding", "multipart/form-data");

// Retrieve the callback function
var fn = $parse(attrs.ngUpload);
// Retrieve the callback function
var fn = $parse(attrs.uploadSubmit);

if (!angular.isFunction(fn)) {
var message = "The expression on the ngUpload directive does not point to a valid function.";
throw message + "\n";
};

element.bind('click', function() {
// create a new iframe
var iframe = angular.element("<iframe id='upload_iframe' name='upload_iframe' border='0' width='0' height='0' style='width: 0px; height: 0px; border: none; display: none' />");

// attach function to load event of the iframe
iframe.bind('load', function () {
// get content - requires jQuery
var content = iframe.contents().find('body').text();
// execute the upload response function in the active scope
scope.$apply(function () {
fn(scope, { content: content, completed: content !== ""});
});
// remove iframe
if (content !== "") { // Fixes a bug in Google Chrome that dispose the iframe before content is ready.
setTimeout(function () { iframe.remove(); }, 250);
}
//if (options.enableControls == null || !(options.enableControls.length >= 0))
element.attr('disabled', null);
element.attr('title', 'Click to start upload.');
});

// add the new iframe to application
//element.parents('form').parent().append(iframe);
scope.uploadForm.parent().append(iframe);

if (!angular.isFunction(fn)) {
var message = "The expression on the ngUpload directive does not point to a valid function.";
throw message + "\n";
}

// Helper function to create new iframe for each form submission
var addNewDisposableIframe = function(submitControl) {
// create a new iframe
var iframe = angular.element("<iframe id='upload_iframe' name='upload_iframe' border='0' width='0' height='0' style='width: 0px; height: 0px; border: none; display: none' />");

// attach function to load event of the iframe
iframe.bind('load', function () {
scope.$apply(function () {
fn(scope, {content: "Please wait...", completed: false
} /* upload not completed */); });

// get content - requires jQuery
var content = iframe.contents().find('body').text();
// execute the upload response function in the active scope
scope.$apply(function () {
fn(scope, { content: content, completed: content !== ""});
});
// remove iframe
if (content !== "") // Fixes a bug in Google Chrome that dispose the iframe before content is ready.
setTimeout(function () { iframe.remove(); }, 250);
var enabled = true;
if (!options.enableControls) {
// disable the submit control on click
element.attr('disabled', 'disabled');
enabled = false;
}

//if (options.enableControls == null || !(options.enableControls.length >= 0))
submitControl.attr('disabled', null);
submitControl.attr('title', 'Click to start upload.');
});
element.attr('title', (enabled ? '[ENABLED]: ' : '[DISABLED]: ') + 'Uploading, please wait...');

// add the new iframe to application
element.parent().append(iframe);
};
// submit the form
scope.uploadForm.submit();

// 1) get the upload submit control(s) on the form (submitters must be decorated with the 'ng-upload-submit' class)
// 2) attach a handler to the controls' click event
var submitControl = element.find('.upload-submit');
submitControl.bind('click', function () {
console.log('foo');

addNewDisposableIframe(submitControl /* pass the submit control */);

scope.$apply(function () { fn(scope, {content: "Please wait...", completed: false } /* upload not completed */); });

var enabled = true;
if (options.enableControls === null || options.enableControls === undefined || options.enableControls.length >= 0) {
// disable the submit control on click
submitControl.attr('disabled', 'disabled');
enabled = false;
}

submitControl.attr('title', (enabled ? '[ENABLED]: ' : '[DISABLED]: ') + 'Uploading, please wait...');

// submit the form
element.submit();
}).attr('title', 'Click to start upload.');
}
else
console.log("No callback function found on the ngUpload directive.");
}).attr('title', 'Click to start upload.');
}
}
}])
.directive('ngUpload', ['$parse', function ($parse) {
return {
restrict: 'AC',
link: function (scope, element, attrs) {
element.attr("target", "upload_iframe");
element.attr("method", "post");
// Append a timestamp field to the url to prevent browser caching results
element.attr("action", element.attr("action") + "?_t=" + new Date().getTime());
element.attr("enctype", "multipart/form-data");
element.attr("encoding", "multipart/form-data");
scope.uploadForm = element;
}
}
};
}]);
}]);
Loading

0 comments on commit 9988098

Please sign in to comment.