I'm trying to implement dropzonejs into an Ionic app.
I've done this before on a AngularJS webapp, when I accessed this site on mobile I could choose between taking a picture or getting one from the gallery of my device.
With Ionic I've implemented dropzonejs the same way, however I'm redirected straight to the gallery of my device instead of presenting me an option to choose between the camera and the gallery.
Could this be some kind of security (I'm using Android for testing atm)? Should I add some config to allow pictures to be taken?
Or does it just don't work in Ionic, any other directives to use?
Thanks in advance!
Here's my code :
Controller:
/**
* DropZone config
*/
angular.extend($scope, $state, {
dropzoneConfig: {
'options': {
autoProcessQueue : false,
maxFilesize : 10,
maxFiles : 10,
parallelUploads : 10,
paramName : "photo",
url : 'https://xxxxxxx.xx/api/photo/add'
},
'eventHandlers': {
'addedfile': function (file) {
$scope.hasPhoto = true
},
'sending': function(file, xhr, formData) {},
'success': function(file, response) {
console.log('Photos uploaded');
},
'queuecomplete': function (file) {
alert('succes');
}
}
}
});
Directive :
angular.module('as.directives')
.directive('dropzone', function() {
return function (scope, element, attrs) {
var config, dropzone;
config = scope[attrs.dropzone];
// create a Dropzone for the element with the given options
dropzone = new Dropzone(element[0], config.options);
// bind the given event handlers
angular.forEach(config.eventHandlers, function (handler, event) {
dropzone.on(event, handler);
// Added this line so we can call $scope.dropzone.processQueue();
// http://stackoverflow.com/questions/28614980/call-function-from-angularjs-directive-for-dropzone-js
scope.dropzone = dropzone;
});
};
});
Related
I have a site that allows a person to import some data. They click a button, and the file select opens and they select a file. When they select a file I open a dialog that they can't close that tells them their data is being imported. Once I get the call back from the api call to import the file, I then close that dialog and open a new one that gives the status of the import.
On Chrome the "please wait while importing" dialog closes as expected. On IE it doesn't. If you use IE 11 it should happen in the following fiddle:
http://jsfiddle.net/og6qsxdw/
You see a ghost like outline of the dialog go up and fade away like its trying to close but the dialog and overlay still remain.
<div ng-controller="MyCtrl">
<input type="file" ng-simple-upload web-api-url="http://www.fakeresponse.com/api/?sleep=5" select-fn="importFileSelected" callback-fn="importDataComplete" />
<script type="text/ng-template" id="templateId">
<div>
Getting Data
</div>
</script>
</div>
JavaScript/AngularJS code:
var myApp = angular.module('myApp', ['ngDialog', 'ngSimpleUpload']);
function MyCtrl($scope, $http, ngDialog) {
$scope.importDataComplete = function() {
$scope.dlg.close();
}
$scope.importFileSelected = function() {
$scope.dlg = ngDialog.open({
template: 'templateId',
className: 'ngdialog-theme-default',
closeByDocument: false,
showClose: false
});
}
}
angular.module('ngSimpleUpload', [])
.directive('ngSimpleUpload', [function() {
return {
scope: {
webApiUrl: '#',
callbackFn: '=',
selectFn: '=',
buttonId: '#'
},
link: function(scope, element, attrs) {
// if button id value exists
if (scope.buttonId) {
$('#' + scope.buttonId).on('click', function() {
// retrieves files from file input
var files = element[0].files;
// will not fire until file(s) are selected
if (files.length == 0) {
console.log('No files detected.');
return false;
}
Upload(files);
});
} else {
// original code, trigger upload on change
element.on('change', function(evt) {
var files = evt.__files_ || (evt.target && evt.target.files);
Upload(files);
// removes file(s) from input
$(this).val('');
});
}
function Upload(files) {
var fd = new FormData();
angular.forEach(files, function(v, k) {
fd.append('file', files[k]);
});
// this tell us the user clicked open instead of cancel so we can start our overlay
scope.selectFn();
return $.ajax({
type: 'GET',
url: scope.webApiUrl,
async: true,
cache: false,
contentType: false,
processData: false
}).done(function(d) {
// callback function in the controller
scope.callbackFn(d);
}).fail(function(x) {
console.log(x);
});
}
}
}
}]);
Alright, so here's the deal. In IE, when you open the dialog, two instances are instantiated. When the upload completes, you have a reference to close the most recent dialog, but one existed milliseconds before as well.
I had originally thought at quick glance that this was just an ugly IE bug, and you had to "keep track" of the instances, however, I failed to take note of jQuery's involvment in your link function. Thusly, my initial solution was a hack/workaround, but better can be done.
It seems that the mixture of the two libraries is the culprit, where Angular and jQuery are not communicating properly. I've inserted a reference below to a ticket that discusses jQuery events with Angular.
jQuery and AngularJS: Bind Events to Changing DOM
Solution
My suggestion, as always in these cases, is not to leverage jQuery on top of Angular. It adds an additional layer of confusion, and requires you to be prudent about maintaining proper coupling between the two (in circumstances such as this).
I have provided a solution, where I clean up your link function. It uses a lot of your existing code, but with the absence of the jQuery bits. It seems to work just fine for me in both Chrome and IE now.
http://plnkr.co/edit/6Z4Rzg1Zm3w5rYyqQqmg?p=preview
link: function(scope, element, attrs) {
console.warn("Element is", element);
// original code, trigger upload on change
element.on('change', function(evt) {
var files = evt.__files_ || (evt.target && evt.target.files);
Upload(files);
});
function Upload(files) {
var fd = new FormData();
angular.forEach(files, function(v, k) {
fd.append('file', files[k]);
console.log("File loaded");
});
// this tell us the user clicked open instead of cancel so we can start our overlay
scope.selectFn();
$http({
url: scope.webApiUrl,
method: "GET",
cache: true
}).success(function(d, status, headers, config) {
scope.callbackFn(d);
}).error(function(data, status, headers, config) {
console.warn("Request failed...");
});
}
}
We are working on a Web application with angularJS and using spring/hibernate.
We are using Linux operating system in production environment and Development environment is Windows.We are trying implement online document editing tool like ms-word in our application.
After some research we are using OnlyOffice https://api.onlyoffice.com/ .
I am using the following angularJs component to use onlyOffice
https://github.com/legalthings/angular-onlyoffice
We are able to integrate it with the application and we can see the opened document in the editor in web browser.
But my changes are not being saved.The control is not reaching the callBackUrl.
Since angularJs component uses onSave method which is not there in OnlyOffice API anymore.So i have changed the code in html and JS file a bit:-
HTML file code is:-
<div ng-controller="DocumentEditController">
<onlyoffice-editor src="{{ trustSrc(document.src) }}"
title="{{ document.name }}">
</onlyoffice-editor>
</div>
And JS file code is:-
angular.module('onlyoffice', []);
angular.module('onlyoffice').directive('onlyofficeEditor', [function () {
function key(k) {
var result = k.replace(new RegExp("[^0-9-.a-zA-Z_=]", "g"), "_") + (new
Date()).getTime();
return result.substring(result.length - Math.min(result.length, 50));
}
var getDocumentType = function (ext) {
if (".docx.doc.odt.rtf.txt.html.htm.mht.pdf.djvu.fb2.epub.xps".indexOf(ext) != -1) return "text";
if (".xls.xlsx.ods.csv".indexOf(ext) != -1) return "spreadsheet";
if (".pps.ppsx.ppt.pptx.odp".indexOf(ext) != -1) return "presentation";
return null;
};
return {
template: '<div id="onlyoffice-editor"></div>',
link: function ($scope, $element, $attrs) {
$scope.$watch(function () {
return $attrs.src;
}, function () {
if (!$attrs.src) return;
var docUrl = $attrs.src;
var docTitle = $attrs.title || docUrl;
var docKey = key(docUrl);
var docType = docUrl.split('?')[0].substring(docUrl.lastIndexOf(".") + 1).trim().toLowerCase();
var documentType = getDocumentType(docType);
var config = {
type: "desktop",
width: '100%',
height: '100%',
documentType: documentType,
document: {
title: docTitle,
url: docUrl,
fileType: docType,
key: docKey,
permissions: {
edit: true,
download: false
}
},
editorConfig: {
mode: 'edit',
callbackUrl:"/documentSave"
},
events: {
onReady: function () {alert("in on ready");
setTimeout(function () {
$scope.$apply(function () {
$scope.ready = true;
});
}, 5000);
},
onError: function (event) {
alert(event.data);
// var url = event.data;
// $scope.save({url: url, close: $scope.close});
},
}
};
//creating object editing
new DocsAPI.DocEditor("onlyoffice-editor", config);
});
}
}
}]);
I changed the documenSave to the fully qualified name using localhost and appname also but that is also not working.
Any help is highly appreciated.
Edit
CallBackUrl is being called now on close of browser button...But our requirement is to save the document on click of save button.
Thanks in advance.
The fact is that clicking on the "Save" button creates a temp file in the document editor. The working document version will only be created after closing the document editor by all users (in ten seconds).
It is impossible to download the changed document in real time (before closing it).
I'm using the Malhar AngularJS Dashboard Framework located here on github: https://github.com/DataTorrent/malhar-angular-dashboard , and a simple demo here: http://datatorrent.github.io/malhar-angular-dashboard/#/ .
Their system uses JQuery Sortable Widgets, which allows me to load up some charts and grids into a dashboard.
The way I load my charts and grids is by using their templateUrl property on the widget definition, as follows :
{
name: myWidgetEnum.TREELIST,
title: 'Tree List',
templateUrl: 'app/shared/gadget-templates/tree-list.html'
}
Here's a more complete sample of the Malhar Widget Definitions, which is where I define my UI "gadgets" to be rendered within the sortable widgets :
(function () {
'use strict';
angular.module('rage')
.factory('widgetDefinitions', ['ColumnChartDataModel', 'TreeListDataModel', 'TreeMapDataModel', 'GridDataModel', widgetDefinitions])
var myWidgetEnum = Object.freeze({
TREELIST: 'chart_treelist',
TREEMAP: 'chart_treemap',
HEATMAP: 'chart_heatmap',
GRID: 'chart_grid'
});
/* Define the widget definitions - base properties are defined in WidgetModel factory.
*/
function widgetDefinitions(ColumnChartDataModel, TreeListDataModel, TreeMapDataModel, GridDataModel) {
var size = { width: '20%', height: 90 };
var fixedSize = { width: '50%', height: 320 }; // keep height as a number, and add 'px' in directive
var initImagePath = 'images4/256x256/';
return [
{
name: myWidgetEnum.TREELIST,
title: 'Tree List',
templateUrl: 'app/shared/gadget-templates/tree-list.html',
dataModelType: TreeListDataModel,
dataModelOptions: {}, // this property will be persisted in DashboardState factory
gadgetType: 'table',
chartType: 'treelist',
settingsModalOptions: { }
},
{
name: myWidgetEnum.HEATMAP,
title: 'Heat Map',
templateUrl: 'app/shared/gadget-templates/grid.html',
dataModelType: GridDataModel,
dataModelOptions: {}, // this property will be persisted in DashboardState factory
gadgetType: 'table',
chartType: 'heatmap',
settingsModalOptions: {} // see 'MainCtrl' controller
}
];
}
})();
And the dashboard options in my main controller :
$scope.dashboardOptions = {
widgetButtons: false, // 'false' makes it a dropdown of options
widgetDefinitions: widgetDefinitions, // see dashboard-widget-factory.js
defaultWidgets: defaultWidgets,
storage: $window.localStorage,
storageId: $scope.defaultDashboardId, // 'rage.ui' - no longer hard code the storage Id - 06/11/2015 BM:
hideWidgetSettings: false,
settingsModalOptions: {
templateUrl: 'app/shared/include/gadget-config-new/gadget-config-container.html',
controller: 'GadgetSettingsCtrl_NEW as settings',
backdrop: true
},
onSettingsClose: function (result, widget) {
jQuery.extend(true, widget, result);
widget.dataModelOptions = result.dataModelOptions;
},
onSettingsDismiss: function (reason) {
console.log('widget settings were dismissed. Reason: ', reason);
}
};
When Malhar first loads up the widgets, it compiles the templateUrl within the JQuery sortable widget.
However, if I launch the widget settings modal and choose a different "widget" from the Widget Definitions list, I'm having an issue when I try to recompile the new templateUrl.
In other words if the first widget loaded up is the TREELIST, then in it's modal settings I choose a new widget called HEATMAP, I need to somehow force a recompile on the new html template that was loaded by Malhar.
Here on github, you can find the main directive, malhar-angular-dashboard.js https://github.com/DataTorrent/malhar-angular-dashboard/blob/master/dist/malhar-angular-dashboard.js , and if you search down for the 'DashboardWidgetCtrl' controller you'll find the $scope.makeTemplateString function as well as the $scope.compileTemplate function further below that.
I'm experimenting with the resolve section of the $modal instance as follows, but this seems to be more of a hack than an elegant solution:
See the angular.element below inside the try...catch section :
// Set resolve and reject callbacks for the result promise
modalInstance.result.then(
function (result) {
// Call the close callback
onClose(result, widget, scope);
// CHECK IF FIRST TIME CONFIGURING THE GADGET - 04/22/2015 BM:
if (!widget.gadgetConfigured) {
widget.gadgetConfigured = true;
widget.setHeight(widget.fixedSize.height);
widget.setWidth(widget.fixedSize.width);
}
scope.$broadcast('widgetSettingsClosed', widget, result);
//AW Persist title change from options editor
scope.$emit('widgetChanged', widget);
// hack to recompile the widget if user has swapped gadget types in gadget config modal - 10/01/2015 BM:
if (widget.chartType == "heatmap" || widget.chartType == "treelist") {
try {
angular.element(document.getElementById('dash')).scope().$$childHead.compileTemplate();
} catch (e) {
console.log("In modalInstance.result.then, cannot compile template " + e);
}
}
},
function (reason) {
// Call the dismiss callback
onDismiss(reason, scope);
}
);
If there's anyone with experience in Mahlar Dashboard, or in compiling directives, I would appreciate any guidance in this area.
thank you,
Bob
I was actually looking to get the content of clipboard using angular JS to simulate a copy paste thing.
I created a directive for copy to clipboard which is using the document.execCommand() method.
Directive
(function() {
app.directive('copyToClipboard', function ($window) {
var body = angular.element($window.document.body);
var textarea = angular.element('<textarea/>');
textarea.css({
position: 'fixed',
opacity: '0'
});
function copy(toCopy) {
textarea.val(toCopy);
body.append(textarea);
textarea[0].select();
try {
var successful = document.execCommand('copy');
if (!successful) throw successful;
} catch (err) {
console.log("failed to copy", toCopy);
}
textarea.remove();
}
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.bind('click', function (e) {
copy(attrs.copyToClipboard);
});
}
}
})
}).call(this);
Html
<button copy-to-clipboard="Copy Me!!!!" class="button">COPY</button>
here's a concise version I use -
function copyToClipboard(data) {
angular.element('<textarea/>')
.css({ 'opacity' : '0', 'position' : 'fixed' })
.text(data)
.appendTo(angular.element($window.document.body))
.select()
.each(function() { document.execCommand('copy') })
.remove();
}
BTW, if using Angular to copy to clipboard with a Chrome Packaged App, do the following:
Add "clipboardRead" and "clipboardWrite" to the "permissions" in the manifest.json.
use ng-click in your view to feed the value to the controller $scope, like: data-ng-click="copyUrlToClipboard(file.webContentLink)"
Put a function in your controller like:
$scope.copyUrlToClipboard = function(url) {
var copyFrom = document.createElement("textarea");
copyFrom.textContent = url;
var body = document.getElementsByTagName('body')[0];
body.appendChild(copyFrom);
copyFrom.select();
document.execCommand('copy');
body.removeChild(copyFrom);
this.flashMessage('over5');
}
I had the same issue and I used angular-clipboard feature[1] which uses new Selection API and Clipboard API available in the latest browsers.
First we have to install angular-clipboard lib, i'm using bower.
$ bower install angular-clipboard --save
To import the module use following in html.
<script src="../../bower_components/angular-clipboard/angular-clipboard.js"></script>
To set values to element using $scope in controller
$scope.textToCopy = 'Testing clip board';
Load the clipboard module using,
angular.module('testmodule', ['angular-clipboard']);
This works for Chrome 43+, Firefox 41+, Opera 29+ and IE10+.
Its simple & worked fine.
[1] https://www.npmjs.com/package/angular-clipboard
Thanks,
A completely different approach:
I need to copy & paste text between windows, so I used this to save (copy) the data to local storage. Then, in the other window, I load it out of local storage, using the same key, and I can then 'paste' is as I like.
I'm new in AngularJS and trying to find the way how to display wait message while data loading? I mean data starts loading, display message and remove it when data loading is done.
I've searched the internet but haven't found anything I need...
<div ng-if="data.dataLoading">
Loading...
</div>
JS
$scope.data.dataLoading = true;
return someService.getData().then(function (results) {
...
}).finally(function () {
$scope.data.dataLoading = false;
});
Depends from where you're loading the data. One solution I used was to create a LoadingService
app.factory('LoadingService', function($rootScope) {
return {
loading : function(message) {
$rootScope.loadingMessage = message;
},
loaded : function() {
$rootScope.loadingMessage = null;
}
}
}).controller('FooController', function($scope,$http,LoadingService) {
$scope.loadSomeData = function() {
LoadingService.loading('Data is loading');
$http.get('/data').finally(function() {
LoadingService.loaded();
});
};
});
Since I had only one place where the message was being displayed I could use RootScope to handle this. If you want to have a loading message multiple times you could write a directive also to handle this like Codezilla posted
Edit: does not work on version 1.3.0 . Use request/response interceptors.
If you want to listen to all requests globally and display a loading widget whenever there's a request pending, you can count the requests using request/response transformers. You simply add a counter and increase on a new request and decrease it on response. I use a provider for that:
$httpProvider
.defaults
.transformRequest
.push(function(data) {
requestNotificationProvider
.fireRequestStarted(data);
return data;
});
And the same for transformResponse. Then the same provider holds the information on how many requests are pending and you can use them in a directive. You can read (& copy/paste the code) a full blog post on that here:
http://www.kvetis.com/2014/01/angularjs-loading-widget.html There's a working demo in attached.
I've answered this question in this StackOverflow article, but here's a recap of what I did.
If you style your code correctly, and make sure all calls to a web service pass through one particular factory function, then you can make that factory function handle showing and hiding your "Please Wait" popup.
Here's the factory function which I use to call all of my GET web services:
myApp.factory('httpGetFactory', function ($http, $q) {
return function (scope, URL) {
// This Factory method calls a GET web service, and displays a modal error message if something goes wrong.
scope.$broadcast('app-start-loading'); // Show the "Please wait" popup
return $http({
url: URL,
method: "GET",
headers: { 'Content-Type': undefined }
}).then(function (response) {
scope.$broadcast('app-finish-loading'); // Hide the "Please wait" popup
if (typeof response.data === 'object') {
return response.data;
} else {
// invalid response
return $q.reject(response.data);
}
}, function (errorResponse) {
scope.$broadcast('app-finish-loading'); // Hide the "Please wait" popup
// The WCF Web Service returned an error.
// Let's display the HTTP Status Code, and any statusText which it returned.
var HTTPErrorNumber = (errorResponse.status == 500) ? "" : "HTTP status code: " + errorResponse.status + "\r\n";
var HTTPErrorStatusText = errorResponse.statusText;
var message = HTTPErrorNumber + HTTPErrorStatusText;
BootstrapDialog.show({
title: 'Error',
message: message,
buttons: [{
label: 'OK',
action: function (dialog) {
dialog.close();
},
draggable: true
}]
});
return $q.reject(errorResponse.data);
});
};
});
This would get called like this:
myApp.webServicesURL = "http://localhost:15021/Service1.svc";
var dsLoadAllEmployees = function (scope)
{
// Load all survey records, from our web server
$scope.LoadingMessage = "Loading Employees data...";
var URL = myApp.webServicesURL + "/loadAllEmployees";
return httpGetFactory(scope, URL);
}
Here's the "Please wait" control which I use on each page..
<please-wait message="{{LoadingMessage}}" ></please-wait>
... and its code looks like this...
myApp.directive('pleaseWait',
function ($parse) {
return {
restrict: 'E',
replace: true,
scope: {
message: '#message'
},
link: function (scope, element, attrs) {
scope.$on('app-start-loading', function () {
element.fadeIn();
});
scope.$on('app-finish-loading', function(){
element.animate({
top: "+=15px",
opacity: "0"
}, 500);
});
},
template: '<div class="cssPleaseWait"><span>{{ message }}</span></div>'
}
});
Using this structure, any of my Angular controllers can load data from a web service in just a few lines, and leave the factory to look after showing/hiding the "Please wait" message and to display any errors which occur:
$scope.LoadAllSurveys = function () {
DataService.dsLoadAllSurveys($scope).then(function (response) {
// Success
$scope.listOfSurveys = response.GetAllSurveysResult;
});
}
Nice, hey ?
I dont know if is the correct way, but I put on my template
<img id="spinner" ng-src="images/spinner.gif" ng-if="!data" >
<div ng-repeat="repo in repos | orderBy: repoSortOrder">...</div>