Yii2: How to show file uploading progress? [duplicate] - file-upload

This question already has an answer here:
Track ajax post progress for fileupload using jquery ajax and FormData
(1 answer)
Closed 4 years ago.
I use Yii2 framework. I would like to show file uploading progress. I don't need complex interface with drag-n-drop or preview. Only progress bar and possible 'cancel' button. Could you point me to a simple example? Thanks.

Eventually I made it with jQuery ajax.
js:
function upload() {
var input = $('#archiveInput');
var files = input.prop('files');
if (files.length > 0) {
var data = new FormData();
data.append('archive', files[0]);
$.ajax({
url: input.data('upload-url'),
type: 'POST',
data: data,
cache: false,
contentType: false,
processData: false,
success: function () {
alert('Upload Complete');
},
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', onProgress);
return myXhr;
}
}
});
}
}
function onProgress(ev) {
if (ev.lengthComputable) {
var progress = parseInt(ev.loaded / ev.total * 100, 10);
$("#progress .progress-bar").css(
"width",
progress + "%"
);
}
}
php controller:
public function actionUpload($idSupply)
{
$directory = FileHelper::normalizePath(Yii::getAlias('#app') . '/uploads/' . $idSupply);
if (!is_dir($directory)) {
FileHelper::createDirectory($directory);
}
$fileName = 'archive.zip';
$filePath = $directory . DIRECTORY_SEPARATOR . $fileName;
if (is_file($filePath)) {
unlink($filePath);
}
move_uploaded_file($_FILES['archive']['tmp_name'], $filePath);
}

Related

Error Ajxa call in asp.net xhr.send( options.hasContent && options.data || null )

I tried to so hard to solve it but couldn't.
I got error
xhr.send( options.hasContent && options.data || null )
while saving data this error shows in Jquery.js.
Code is working perfectly in debug mode in vs 2022. I can save data in debug mode. But when
I compile (Publish) this project. I hosted in IIS and every things working perfectly but not in this form When I try to post data then I got same error.
I tried to send header but not working..
var token =
$('input:hidden[name="__RequestVerificationToken"]').val();
headers: { RequestVerificationToken: token },
var detailsList = new Array();
var detailsObj = new Object();
$("#tblDropItem tbody tr").each(function () {
let row = $(this);
let itemId = Number(row.find('.item_detl').attr('purItem_id'));
detailsObj = {
ItemId: itemId,
ItemName: row.find(".item_detl").val(),
Quantity: parseFloat(row.find(".quantity_detl").val()),
UnitId: Number(row.find('.unit_detl').attr('unit_id')),
Rate: parseFloat(row.find(".rate_detl").val()),
Amount: parseFloat(row.find(".amount_detl").val()),
}
if (detailsObj.ItemName) {
detailsList.push(detailsObj);
}
});
var postData = {
PurMode: $("#PurMode").val(),
PurDate: $("#PurDate").val(),
SupId: $("#SupId option:selected").val(),
SubAmount: parseFloat($("#SubAmount").val()),
Discount: parseFloat($("#DiscountPercent").val()),
DiscountAmount: parseFloat($("#Discount").val()),
TotalAmount: parseFloat($("#TotalAmount").val()),
Remarks: $("#Remarks").val(),
Taxable: parseFloat($("#Taxable").val()),
VatAmount: parseFloat($("#VatAmount").val()),
VATable: parseFloat($("#VATable option:selected").val())
PurchaseDetailItemList: detailsList,
__RequestVerificationToken: $("input[name=__RequestVerificationToken]").val(),
}
$.ajax({
type: "POST",
url: "/Purchase/SavePurchase",
dataType: 'JSON',
data: postData,
async:false,
success: function (result) {
toastr.success('Data Saved Successfully');
window.location = "#Url.Content("~/Purchase/Index")";
},
error: function (result) {
toastr.error("Cann't Save Data.");
}
});
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult SavePurchase(PurchaseDTO model)
{
if (!ModelState.IsValid)
{
return Json("error");
}
//code...
}
Can you please suggest any mistake..
Everything is correct, maybe you have hosted incorrectly in iis, make sure your post url is valid in console.

Updating the image in laravel 8 + inertia, validation error even the fields are filled

I'm working with Laravel 8 + inertiajs. I can create a product with or without an image. But when I try to update a product and upload a new image, the validation looks for the required field even they're already filled.
here is my input field:
<input name="images" type="file" #input="form.images = $event.target.files[0]" />
in my vue:
props: {
product: Object,
categories: Array
},
data() {
return {
form: this.$inertia.form({
name: this.product.name,
category_id: this.product.category_id,
description: this.product.description,
date: this.product.date,
images: this.product.images
})
}
},
methods: {
update() {
this.form.put(this.route('products.update', this.product.id, {
preserveState: true
}))
},
}
})
my update controller:
public function update(UpdateProductRequest $request, Product $product)
{
$inputs = $request->validated();
if ($request->hasFile('images')) {
$filename = $request->images->getClientOriginalName();
$file = $request->images->storeAs(('images'), $filename);
$product->images = $file;
$inputs['images'] = $product->images;
}
$product->name = $inputs['name'];
$product->category_id = $inputs['category_id'];
$product->description = $inputs['description'];
$product->date = $inputs['date'];
$product->update();
session()->flash('flash.banner', 'Product Updated Successfuly');
session()->flash('flash.bannerStyle', 'success');
return redirect()->route('products.index');
}
multipart/form-data request is not natively supported in some languages for the put,patch or delete methods. The workaround here is to simply upload files using post instead.
Some frameworks, such as Laravel and Rails, support form method spoofing, which allows you to upload the files using post, but have the framework handle the request as a put or patch request. This is done by including a _method attribute in the data of your request.
Inertia.post(`/users/${user.id}`, {
_method: 'put',
avatar: form.avatar,
})

PDF Blob is not showing content, Angular 2

I have problem very similar to this PDF Blob - Pop up window not showing content, but I am using Angular 2. The response on question was to set responseType to arrayBuffer, but it not works in Angular 2, the error is the reponseType does not exist in type RequestOptionsArgs. I also tried to extend it by BrowserXhr, but still not work (https://github.com/angular/http/issues/83).
My code is:
createPDF(customerServiceId: string) {
console.log("Sending GET on " + this.getPDFUrl + "/" + customerServiceId);
this._http.get(this.getPDFUrl + '/' + customerServiceId).subscribe(
(data) => {
this.handleResponse(data);
});
}
And the handleResponse method:
handleResponse(data: any) {
console.log("[Receipt service] GET PDF byte array " + JSON.stringify(data));
var file = new Blob([data._body], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
}
I also tried to saveAs method from FileSaver.js, but it is the same problem, pdf opens, but the content is not displayed. Thanks
I had a lot of problems with downloading and showing content of PDF, I probably wasted a day or two to fix it, so I'll post working example of how to successfully download PDF or open it in new tab:
myService.ts
downloadPDF(): any {
return this._http.get(url, { responseType: ResponseContentType.Blob }).map(
(res) => {
return new Blob([res.blob()], { type: 'application/pdf' })
}
}
myComponent.ts
this.myService.downloadPDF().subscribe(
(res) => {
saveAs(res, "myPDF.pdf"); //if you want to save it - you need file-saver for this : https://www.npmjs.com/package/file-saver
var fileURL = URL.createObjectURL(res);
window.open(fileURL); / if you want to open it in new tab
}
);
NOTE
It is also worth mentioning that if you are extending Http class to add headers to all your requests or something like that, it can also create problems for downloading PDF because you will override RequestOptions, which is where we add responseType: ResponseContentType.Blob and this will get you The request body isn't either a blob or an array buffer error.
ANGULAR 5
I had the same problem which I lost few days on that.
Here my answer may help others, which helped to render pdf.
For me even though if i mention as responseType : 'arraybuffer', it was unable to take it.
For that you need to mention as responseType : 'arraybuffer' as 'json'.(Reference)
Working code
downloadPDF(): any {
return this._http.get(url, { responseType: 'blob' as 'json' }).subscribe((res) => {
var file = new Blob([res], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
}
}
Referred from the below link
https://github.com/angular/angular/issues/18586
Amit,
You can rename the filename by adding a variable to the end of the string
so saveAs(res, "myPDF.pdf");
Becomes
saveAs(res, "myPDF_"+someVariable+".pdf");
where someVariable might be a counter or my personal favorite a date time string.
This worked for me
var req = this.getPreviewPDFRequest(fd);
this.postData(environment.previewPDFRFR, req).then(res => {
res.blob().then(blob => {
console.clear();
console.log(req);
console.log(JSON.stringify(req));
const fileURL = URL.createObjectURL(blob);
window.open(fileURL, '', 'height=650,width=840');
})
});
Server side (Java/Jetty) : REST service that returns a File Response
The File Response itself will automatically be parsed into a pdf blob file by Jetty (because of the annotation #Produces("application/pdf") ), in other to be send to and read by the web client
#GET
#Path("/download-pdf/{id}")
#Produces("application/pdf")
public Response downloadPDF(#ApiParam(value = "Id of the report record")
#PathParam("id") Long id) {
ResponseBuilder response = null;
try {
PDFReportService service = new PDFReportService();
File reportFile = service.getPDFReportFile(id);
response = Response.ok((Object) reportFile);
response.header("Content-Disposition","attachment; filename="+reportFile.getName());
return response.build();
} catch (DomainException e) {
response = Response.serverError().entity("server.error");
}
return response.build();
}
Client side code (angular 2) : grab the blob and print it in a new browser tab
The key is to insure that you read the request reponse as a blob (as the server returned a blob; in my case)
Now, I tried so hard but I finally figured out that Angular 2 has not implemented any function to handle blob responses (neither res['_body'], nor res.blob() worked for me)
So I found no other workaround than using JQuery ajax to perform that file blob request, like following:
public downloadPDFFile() {
let fileURL = serverURL+"/download-pdf/"+id;
let userToken: string = your_token;
showWaitingLoader();
$.ajax({
url: fileURL,
cache: false,
headers: {
"Content-Type": "application/json",
"Authorization": "Basic " + userToken
},
xhrFields: {
responseType: 'blob' //Most important : configure the response type as a blob
},
success: function(blobFile) {
const url = window.URL.createObjectURL(blobFile);
window.open(url);
stopWaitingLoader();
},
error: function(e){
console.log("DOWNLOAD ERROR :", e);
}
});
}

How we get and post api in Titanium alloy?

How can we get and post api in Titanium alloy?
I am having the api of userDetails, I just want that how can i code to get the data from api.
function getUserDetails(){
}
Thanks in advance.
As you mentioned, you are using Titanium alloy.
So another approach be to extend the Alloy's Model and Collection ( which are based on backbone.js concept ).
There are already some implementation at RestAPI Sync Adapter also proper description/usage at Titanium RestApi sync.
I also provide the description and methodology used, in-case link gets broken:
Create a Model : Alloy Models are extensions of Backbone.js Models, so when you're defining specific information about your data, you do it by implementing certain methods common to all Backbone Models, therefor overriding the parent methods. Here we will override the url() method of backbone to allow our custom url endpoint.
Path :/app/models/node.js
exports.definition = {
config: {
adapter: {
type: "rest",
collection_name: "node"
}
},
extendCollection: function(Collection) {
_.extend(Collection.prototype, {
url: function() {
return "http://www.example.com/ws/node";
},
});
return Collection;
}
};
Configure a REST sync adapter : The main purpose of a sync adapter is to override Backbone's default sync method with something that fetches your data. In our example, we'll run through a few integrity checks before calling a function to fetch our data using a Ti.Network.createHTTPClient() call. This will create an object that we can attach headers and handlers to and eventually open and send an xml http request to our server so we can then fetch the data and apply it to our collection.
Path :/app/assets/alloy/sync/rest.js (you may have to create alloy/sync folders first)
// Override the Backbone.sync method with our own sync
functionmodule.exports.sync = function (method, model, opts)
{
var methodMap = {
'create': 'POST',
'read': 'GET',
'update': 'PUT',
'delete': 'DELETE'
};
var type = methodMap[method];
var params = _.extend(
{}, opts);
params.type = type;
//set default headers
params.headers = params.headers || {};
// We need to ensure that we have a base url.
if (!params.url)
{
params.url = model.url();
if (!params.url)
{
Ti.API.error("[REST API] ERROR: NO BASE URL");
return;
}
}
//json data transfers
params.headers['Content-Type'] = 'application/json';
switch (method)
{
case 'delete':
case 'create':
case 'update':
throw "Not Implemented";
break;
case 'read':
fetchData(params, function (_response)
{
if (_response.success)
{
var data = JSON.parse(_response.responseText);
params.success(data, _response.responseText);
}
else
{
params.error(JSON.parse(_response.responseText), _response.responseText);
Ti.API.error('[REST API] ERROR: ' + _response.responseText);
}
});
break;
}
};
function fetchData(_options, _callback)
{
var xhr = Ti.Network.createHTTPClient(
{
timeout: 5000
});
//Prepare the request
xhr.open(_options.type, _options.url);
xhr.onload = function (e)
{
_callback(
{
success: true,
responseText: this.responseText || null,
responseData: this.responseData || null
});
};
//Handle error
xhr.onerror = function (e)
{
_callback(
{
'success': false,
'responseText': e.error
});
Ti.API.error('[REST API] fetchData ERROR: ' + xhr.responseText);
};
for (var header in _options.headers)
{
xhr.setRequestHeader(header, _options.headers[header]);
}
if (_options.beforeSend)
{
_options.beforeSend(xhr);
}
xhr.send(_options.data || null);
}
//we need underscore
var _ = require("alloy/underscore")._;
Setup your View for Model-view binding : Titanium has a feature called Model-View binding, which allows you to create repeatable objects in part of a view for each model in a collection. In our example we'll use a TableView element with the dataCollection property set to node, which is the name of our model, and we'll create a TableViewRow element inside. The row based element will magically repeat for every item in the collection.
Path :/app/views/index.xml
<Alloy>
<Collection src="node">
<Window class="container">
<TableView id="nodeTable" dataCollection="node">
<TableViewRow title="{title}" color="black" />
</TableView>
</Window>
</Alloy>
Finally Controller : Binding the Model to the View requires almost no code at the controller level, the only thing we have to do here is load our collection and initiate a fetch command and the data will be ready to be bound to the view.
Path :/app/controllers/index.js
$.index.open();
var node = Alloy.Collections.node;
node.fetch();
Further reading :
Alloy Models
Sync Adapters
Hope it is helpful.
this is the solution for your problem:-
var request = Titanium.Network.createHTTPClient();
var done=false;
request.onload = function() {
try {
if (this.readyState == 4 && !done) {
done=true;
if(this.status===200){
var content = JSON.parse(this.responseText);
}else{
alert('error code' + this.status);
}
}
} catch (err) {
Titanium.API.error(err);
Titanium.UI.createAlertDialog({
message : err,
title : "Remote Server Error"
});
}
};
request.onerror = function(e) {
Ti.API.info(e.error);
};
request.open("POST", "http://test.com");
request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
request.send({ test: 'test'});
if you don't get your answer please let me know.
Thanks

How to get value of KendoUI TreeView

Firstable sorry for my English. I've problem with KendoUI TreeView control on ASP.NET MVC4.
<div class="treeview-back">
#(Html.Kendo().TreeView()
.Name("treeview-left")
.DragAndDrop(true)
.Events(ItemAction)
.BindTo(Model)
)
I got treeview and binded event OnDrop:
function OnDrop(e) {
dropped = GetValueFromTags(e.destinationNode.innerHTML);
inDrag = !inDrag;
OnHover();
e.setValid(e.valid && id > 10000);
if (e.valid && id > 10000) {
var webMethod = "/Sitemap/UpdateData";
var data = $("div.treeview-back").find("span.items").text();
//var data = $("div.treeview-back").data("kendoTreeView").dataSource.data();
console.log(data);
$.ajax({
type: "POST",
url: webMethod,
data: data,
contentType: "application/json",
dataType: "json",
converters: {
'text json': true
},
success: function(data) {
},
error: function(data) {
console.log("error: " + data);
}
});
}
}
And my action in Controller:
[HttpPost]
public ActionResult UpdateData(IEnumerable<TreeViewItemModel> data)
{
// some database operations here
return Json(data);
}
I would like to send current state of my treeview to action. Problem is current method is sending null. I was able to send datasource but it was orginal data (that what i binding to control on start), not the current.
Thanks for help,
Ɓukasz