I am looking for the easiest way to post image via angular and django rest.
I've took some code samples and combined to this, but I am still getting error:
Upload a valid image. The file you uploaded was either not an image or a corrupted image.
Maybe someone has a good eye and could easily see what I am missing here?
P.S.
libjpeg-dev is already the newest version
javascript.js
/* global angular */
var products = angular.module('products',['ngCookies']);
products.config(function($interpolateProvider) {
//allow django templates and angular to co-exist
$interpolateProvider.startSymbol('{[{');
$interpolateProvider.endSymbol('}]}');
});
products.run(function($rootScope, $log, $http, $cookies) {
$http.defaults.headers.common['X-CSRFToken'] = $cookies['csrftoken'];
});
products.factory('ModelUtils', function($http, $log) {
var handleErrors = function(serverResponse, status, errorDestination) {
if (angular.isDefined(errorDestination)) {
if (status >= 500) {
errorDestination.form = 'Server Error: ' + status;
} else if (status >= 401) {
errorDestination.form = 'Unauthorized Error: ' + status;
} else {
angular.forEach(serverResponse, function(value, key) {
if (key != '__all__') {
errorDestination[key] = angular.isArray(value) ? value.join("<br/>") : value;
} else {
errorDestination.form = errorDestination.form || '' + key + ':' + angular.isArray(value) ? value.join("<br/>") : value;
}
});
}
}
};
var ModelUtils = {
get: function(url,id) {
$http.get(url + id + '/').then(function(response){response.data});
},
create: function(url, obj, errors) {
//TODO
//obj.author = username;
return $http.post(url, obj).
success(function(response, status, headers, config) {
angular.extend(obj, response);
}).
error(function(response, status, headers, config) {
handleErrors(response, status, errors);
});
},
save: function(url, obj, errors) {
if (angular.isDefined(obj.id)) {
return $http.put(url + obj.id + '/', obj).
success(function(response, status, headers, config) {
angular.extend(obj, response);
});
error(function(response, status, headers, config) {
handleErrors(response, status, errors);
});
} else {
return this.create(url, obj, errors);
}
},
del: function(url, obj) {
console.log(url, obj, obj.id);
return $http.delete(url + obj.id + '/');
}
};
return ModelUtils;
});
products.controller('ListCtrl', function ListCtrl($scope, $log, $http, ModelUtils) {
// dcl variables
$scope.tempUrlJs = document.getElementById("tempVar1").value;
// just a dummy init function
$scope.initialize = function(data) {
$log.log('initialize',data);
$scope.initData = data;
};
$scope.loaditems = function() {
console.log('hello');
$scope.items = $http.get('/api/images/').then(function(response){
return response.data;
});
};
//mainFlow
$scope.loaditems($scope.tempUrlJs);
$scope.currentitem = {};
$scope.errors = {};
console.log('hello');
$scope.saveitem = function() {
console.log('hello');
ModelUtils.save('/api/images/',$scope.currentitem, $scope.errors).then(function(){
$scope.loaditems();
$scope.currentitem = {};
});
};
$scope.delitem = function(item) {
console.log('0');
ModelUtils.del('/api/images/',item).then(function(){
console.log('10');
$scope.loaditems();
});
};
});
products.controller('subListCtrl', function ListCtrl($scope, $log, $http, ModelUtils) {
// dcl variables
$scope.tempUrlJs = '/api/ingredients/'
//document.getElementById("tempVar2").value;
// just a dummy init function
$scope.initialize = function(data) {
$log.log('initialize',data);
$scope.initData = data;
};
$scope.loaditems = function(tempUrlJs) {
$scope.items = $http.get(tempUrlJs).then(function(response){
return response.data;
});
};
$scope.saveitem = function() {
ModelUtils.save('/api/ingredients/',$scope.currentitem, $scope.errors).then(function(){
$scope.loaditems();
$scope.currentitem = {};
});
};
//mainFlow
$scope.loaditems($scope.tempUrlJs);
$scope.currentitem = {};
$scope.errors = {};
});
index.html
<body ng-app="products">
<div ng-controller="ListCtrl">
<h3>Insert image</h3>
<form>
<ul>
<li>Title: <input type="text" name="title" ng-model="currentitem.title"/><span class="error">{[{ errors.title }]}</span></li>
<li>Description: <input type="text" name="description" ng-model="currentitem.description"/><span class="error">{[{ errors.description }]}</span></li>
<li>Image: <input type="file" name="image" ngf-select ng-model ="currentitem.image" accept="image/*"/><span class="error">{[{ errors.image }]}</span></li>
</ul>
<button ng-click="saveitem()">Save</button>
<pre>currentitem:{[{ currentitem | json }]}</pre>
</form>
serializers.py
class Base64ImageField(serializers.ImageField):
def to_internal_value(self, data):
from django.core.files.base import ContentFile
import base64
import six
import uuid
def decode_base64(data):
missing_padding = len(data) % 4
if missing_padding != 0:
data += b'='* (4 - missing_padding)
return base64.decodestring(data)
if isinstance(data, six.string_types):
if 'data:' in data and ';base64,' in data:
header, data = data.split(';base64,')
try:
data = decode_base64(data)
decoded_file = base64.b64decode(data)
#decoded_file = decode_base64(decoded_file)
except TypeError:
self.fail('invalid_image')
file_name = str(uuid.uuid4())[:12] # 12 characters are more than enough
file_extension = self.get_file_extension(file_name, decoded_file)
complete_file_name = "%s.%s" % (file_name, file_extension, )
data = ContentFile(decoded_file, name=complete_file_name)
return super(Base64ImageField, self).to_internal_value(data)
def get_file_extension(self, file_name, decoded_file):
import imghdr
extension = imghdr.what(file_name, decoded_file)
extension = "jpg" if extension == "jpeg" else extension
return extension
class UploadedImageSerializer(serializers.ModelSerializer):
image = Base64ImageField(
max_length=None, use_url=True,
)
class Meta:
model = image
fields = ('pk', 'image', 'thumbnail', 'title', 'description', )
read_only_fields = ('thumbnail',)
views.py
class UploadedImages(TemplateView):
template_name = 'image.html'
queryset = image.objects.all()
serializer_class = UploadedImageSerializer
class UploadedImagesApi(generics.ListCreateAPIView):
queryset = image.objects.all()
model = image
serializer_class = UploadedImageSerializer
models.py
def scramble_uploaded_filename(instance, filename):
extension = filename.split(".")[-1]
return "{}.{}".format(uuid.uuid4(), extension)
def create_thumbnail(input_image, thumbnail_size=(256, 256)):
if not input_image or input_image == "":
return
image = Image.open(input_image)
image.thumbnail(thumbnail_size, Image.ANTIALIAS)
filename = scramble_uploaded_filename(None, os.path.basename(input_image.name))
arrdata = filename.split(".")
extension = arrdata.pop()
basename = "".join(arrdata)
new_filename = basename + "_thumb." + extension
image.save(os.path.join(settings.MEDIA_ROOT, new_filename))
return new_filename
class image(models.Model):
image = models.ImageField("Uploaded image", upload_to=scramble_uploaded_filename)
thumbnail = models.ImageField("Thumbnail of uploaded image", blank=True)
title = models.CharField("Title of the uploaded image", max_length=255, default="Unknown Picture")
description = models.TextField("Description of the uploaded image", default="")
def __str__(self):
return self.title
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
self.thumbnail = create_thumbnail(self.image)
super(image, self).save(force_update=force_update)
I don't know angular so this might be completely wrong, but don't you always need enctype="multipart/form-data" in your <form> tag to upload images?
Related
AngularJS 1.59
This API call works with $http.get.
JS ViewModel
$scope.placeOrder = function () { //'api/order/create'
var order = { AccountId : accountId, Amount : $scope.subTotal,
Tax: $scope.tax, Shipping: $scope.shipping }
var orderJSON = JSON.stringify(order);
viewModelHelper.apiGet('api/order/create', { params: { order: orderJSON } },
function (result) {
var orderId = result.data;
});
}
App.js
self.apiGet = function (uri, data, success, failure, always) {
self.isLoading = true;
self.modelIsValid = true;
$http.get(AlbumApp.rootPath + uri, data)
.then(function (result) {
success(result);
if (always != null)
always();
self.isLoading = false;
}, function (result) {
if (failure == null) {
if (result.status != 400)
self.modelErrors = [result.status + ': ' + result.statusText +
' - ' + result.data];
else
self.modelErrors = [result.data + ''];
self.modelIsValid = false;
}
else
failure(result);
if (always != null)
always();
self.isLoading = false;
});
}
self.apiPost = function (uri, data, success, failure, always) {
self.isLoading = true;
self.modelIsValid = true;
$http.post(AlbumApp.rootPath + uri, data)
.then(function (result) {
success(result);
if (always != null)
always();
self.isLoading = false;
}, function (result) {
if (failure == null) {
if (result.status != 400)
self.modelErrors = [result.status + ': ' + result.statusText + ' - ' + result.data];
else self.modelErrors = [result.data];
self.modelIsValid = false;
}
else failure(result);
if (always != null) always();
self.isLoading = false;
});
}
APIController
[HttpGet]
[Route("create")]
public IHttpActionResult Create(string order) {
var _order = JsonConvert.DeserializeObject<Order>(order); ... }
But since this is a Create function I want to use $http.post. When I change the call to
$scope.placeOrder = function () { //'api/order/create'
var order = { AccountId : accountId, Amount : $scope.subTotal,
Tax: $scope.tax, Shipping: $scope.shipping }
var orderJSON = JSON.stringify(order);
viewModelHelper.apiPost('api/order/create', { params: { order: orderJSON } },
//null,
function (result) {
var orderId = result.data;
});
}
and my controller Action to
[HttpPost]
[Route("create")]
public IHttpActionResult Create(string order) {
var _order = JsonConvert.DeserializeObject<Order>(order); ... }
I get a 404 error:
<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://localhost:50597/api/order/create'.
</Message>
<MessageDetail>
No action was found on the controller 'OrderApi' that matches the request.
</MessageDetail>
</Error>
Is this a bug or am I missing some conceptual point or do I have an error in my code?
Solution: (Thank you Giovani)
params: needs to be passed to the config in the $http.get and $http.post. The two methods have different signatures.
In apiGet renamed data to config.
In apiPost added a config.
In apiPost call added a null so the params: is passed to config rather than data.
App.js
self.apiGet = function (uri, config, success, failure, always) {
self.isLoading = true;
self.modelIsValid = true;
$http.get(AlbumApp.rootPath + uri, config)
...
self.apiPost = function (uri, data, config, success, failure, always) {
self.isLoading = true;
self.modelIsValid = true;
$http.post(AlbumApp.rootPath + uri, data, config)
JS ViewModel
$scope.placeOrder = function () { //'api/order/create'
var order = { AccountId : accountId, Amount : $scope.subTotal,
Tax: $scope.tax, Shipping: $scope.shipping }
var orderJSON = JSON.stringify(order);
viewModelHelper.apiPost('api/order/create', null, { params: { order: orderJSON } },
function (result) {
var orderId = result.data;
}); }
$http.get() and $http.post() have a different method signature. more info
$http.get(<URL>, <DATA (params, responseType, etc..)>)
$http.post(<URL>, <BODY_DATA>, <DATA (params, responseType, etc..)>
here is my all code i am trying to upload small image and large image separate but angularjs not let me allow to do this, it only taking one file but not taking other one. plz anyone help with this. thanks in advance.
<div ng-app="eventModule" >
<div ng-controller="eventController">
<div>
<span >Thumbnail Image</span>
<input type="file" id="fileToUpload" onchange="angular.element(this).scope().selectThumbnail(this.files)" accept="image/*" />
</div>
<div>
<span >Large Image</span>
<input type="file" onchange="angular.element(this).scope().selectLargeImage(this.files)" class="LargeImageSubCategory" />
</div>
</div>
<span data-ng-click="SaveFile()">Submit</span>
</div>
<script>
var eventModule = angular.module('eventModule', []);
eventModule.controller('eventController', function ($scope,ArticleService, $http, $sce) {
$scope.selectThumbnail = function (file) {
$scope.SelectedThumbnail = file[0];
}
$scope.selectLargeImage = function (file) {
$scope.SelectedLargeImage = file[0];
}
$scope.SaveFile = function () {
$scope.IsFormSubmitted = true;
$scope.Message = "";
ArticleService.UploadFile($scope.SelectedThumbnail, $scope.SelectedLargeImage).then(function (d) {
alert(d.Message);
ClearForm();
}, function (e) {
alert(e);
});
};
});
eventModule.service("ArticleService", function ($http, $q) {
this.UploadFile = function (Thumbnail, LargeImage, TitleHeading, Topic, SmallDesc, LargeDesc) {
var formData = new FormData();
formData.append("Thumbnail", Thumbnail);
formData.append("LargeImage", LargeImage);
// here when i am trying to send two files so controller is not called
//and function is breaking and alert is comming "File Upload Failed"
formData.append("TitleHeading", TitleHeading);
formData.append("Topic", Topic);
var defer = $q.defer();
$http.post("/Articles/SaveFiles", formData,
{
withCredentials: true,
headers: { 'Content-Type': undefined },
transformRequest: angular.identity
}).success(function (d) {
defer.resolve(d);
}).error(function () {
defer.reject("File Upload Failed!");
});
return defer.promise;
}
});
</script>
//And My ArticlesController.cs code is
[HttpPost]
public JsonResult SaveFiles(string TitleHeading, string Topic)
{
string Message, fileName, actualFileName;
Message = fileName = actualFileName = string.Empty;
bool flag = false;
if (Request.Files != null)
{
var file = Request.Files[0];
actualFileName = file.FileName;
fileName = Guid.NewGuid() + Path.GetExtension(file.FileName);
int size = file.ContentLength;
try
{
file.SaveAs(Path.Combine(Server.MapPath("~/UploadedFiles"), fileName));
using (TCDataClassesDataContext dc = new TCDataClassesDataContext())
{
Article insert = new Article();
insert.ArticleId = Guid.NewGuid();
insert.TitleHeading = TitleHeading;
insert.SmallImagePath = fileName;
dc.Articles.InsertOnSubmit(insert);
dc.SubmitChanges();
Message = "File uploaded successfully";
flag = true;
}
}
catch (Exception)
{
Message = "File upload failed! Please try again";
}}
return new JsonResult { Data = new { Message = Message, Status = flag } };
}
You are appending the files to the formdata, thus you need to specify the Thumbnail and LargeImage as parameters of your MVC controller. Please see below:
[HttpPost]
public JsonResult SaveFiles(
HttpPostedFileBase thumbnail
, HttpPostedFileBase largeImage
, string titleHeading
, string topic)
{
string Message, fileName, actualFileName;
Message = fileName = actualFileName = string.Empty;
bool flag = false;
if (thumbnail != null && thumbnail.ContentLength != 0)
{
SaveFile(thumbnail);
}
if (largeImage != null && largeImage.ContentLength != 0)
{
SaveFile(largeImage);
}
return new JsonResult { Data = new { Message = Message, Status = flag } };
}
private void SaveFile(
HttpPostedFileBase httpFile)
{
var actualFileName = httpFile.FileName;
var fileName = Guid.NewGuid() + Path.GetExtension(httpFile.FileName);
int size = httpFile.ContentLength;
try
{
httpFile.SaveAs(Path.Combine(Server.MapPath("~/UploadedFiles"), fileName));
using (TCDataClassesDataContext dc = new TCDataClassesDataContext())
{
Article insert = new Article();
insert.ArticleId = Guid.NewGuid();
insert.TitleHeading = TitleHeading;
insert.SmallImagePath = fileName;
dc.Articles.InsertOnSubmit(insert);
dc.SubmitChanges();
Message = "File uploaded successfully";
flag = true;
}
}
catch (Exception)
{
Message = "File upload failed! Please try again";
}
}
I am implementing an input which allow to select multiple values as tags. I am working with angular-ui-bootstrap-typeahead
The following example with dummy data works fine:
view:
<script type="text/ng-template" id="form_field_ref">
<div class='container-fluid' ng-controller="typeHeadTestCtrl">
<input type="text" ng-model="selected" typeahead="x.formatted_address for x in dynamicSearch($viewValue, field.displayName)" class="form-control" typeahead-on-select='onSelect($item, field)'>
</div>
</script>
part of controller:
$scope.getLocation = function(val) {
return $http.get('http://maps.googleapis.com/maps/api/geocode/json', {
params: {
address: val,
sensor: false
}
}).then(function(response){
console.log(response);
return response.data.results.map(function(item){
console.log(item);
//items attribute=> address_components, formatted_address, place_id....
return item;
});
});
};
But when I try to connect to my actual data I get the following error:
TypeError: Cannot read property 'length' of undefined
at ui-bootstrap-tpls.js:3637
at processQueue (angular.js:13170)
at angular.js:13186
at Scope.$eval (angular.js:14383)
at Scope.$digest (angular.js:14199)
at Scope.$apply (angular.js:14488)
at $$debounceViewValueCommit (angular.js:20944)
at $setViewValue (angular.js:20916)
at HTMLInputElement.listener (angular.js:19632)
at HTMLInputElement.eventHandler (angular.js:3011)
Here is the code that fails:
view:
<input type="text" ng-model="selected" typeahead="x.theVal for x in dynamicSearch($viewValue, field.displayName)" class="form-control" typeahead-on-select='onSelect($item, field)'>
the parts of the controller:
dynamicSearch() prepares what data to request on call of getDbRefDocs():
$scope.dynamicSearch = function(searchTerm, name) {
var allowed = {};
var classString = "";
allowed = datamodel.classes[$routeParams.class].attribute[name].allowed;
for (key in allowed){
classString = classString + key + "|";
}
//remove last pipeline
classString = classString.slice(0, -1);
$scope.getDbRefDocs(searchTerm, name, classString);
};
$scope.getDbRefDocs = function(searchTerm, name, classString) {
var url = '/api/v2/docs/' + classString;
return $http.get(url, {
params: {
'>displayName': searchTerm,
count: 5
}
}).then(function(response){
var data = response.data.data;
console.log('data:'+data);
var requested = [];
angular.forEach(data.requested, function(searchTerm, k, o) {
requested.push(createDBOifNecessary(searchTerm));
});
$scope.item=[];
$scope.options=[];
$scope.options[name] = [];
for (key in requested) {
if (requested.hasOwnProperty(key)) {
//This is the storing value
//console.log(requested[key].cid);
//this is the display value
//console.log(requested[key].attributes.displayName[0]);
$scope.options[name][key] = requested[key].attributes.displayName[0];
$scope.item.push({
'theName':requested[key].attributes.displayName[0],
'theVal':requested[key].cid
});
}
}
console.log('item:'+$scope.item);
return $scope.item;
});
};
This last console.log returns the required data correctly!
For what I have been able to read the problem is related to the promise of the server request... but i am stuck!
I am not sure what was failing because i was receiving the expected data.
I think as someone mentioned it could be related to the manipulation of the response, delaying it...
In stead I added an event trigger that updates the array the typeahead attribute reads from and it now works fine. As well the typeahead-wait-ms is required cause my server response is between 20 and 30ms so just to be safe I set it to 200ms.
working code:
view: displays the values of the array "item"(item.theName == x.theName)
<input type="text" ng-model="selected" typeahead="x.theName for x in item" ng-change="dynamicSearch($viewValue, field.displayName)" typeahead-wait-ms="1000" class="form-control" typeahead-on-select='onSelect($item, field)'>
Controller functions:
On ng-change ->dynamicSearch() =>define what data request and call the request
$scope.dynamicSearch = function(searchTerm, name) {
var allowed = {};
var classString = "";
allowed = datamodel.classes[$routeParams.class].attribute[name].allowed;
for (key in allowed){
classString = classString + key + "|";
}
classString = classString.slice(0, -1);
$scope.getDbRefDocs(searchTerm, name, classString);
};
On call of getDbRefDocs() => i define values for the array "item"
$scope.getDbRefDocs = function(searchTerm, name, classString) {
var url = '/api/v2/docs/' + classString;
$http.get(url, {
params: {
'>displayName': searchTerm,
count: 5
}
}).then(function(response){
var data = response.data.data;
var requested = [];
angular.forEach(data.requested, function(searchTerm, k, o) {
requested.push(createDBOifNecessary(searchTerm));
});
$scope.item=[];
for (key in requested) {
if (requested.hasOwnProperty(key)) {
$scope.item.push({
'theName':requested[key].attributes.displayName[0],
'theVal':requested[key].cid
});
}
}
});
};
When item is selected from the available options of "item" => typeahead-on-select='onSelect($item, field)' => I store item.theVal:
$scope.onSelect = function (item, field) {
field.theValues[field.theValues.length] = item.theVal;
};
I always manage pagination with angular
retrieve all the data from the server
and cache it client side (simply put it in a service)
now I have to cope with quite lot of data
ie 10000/100000.
I'm wondering if can get into trouble
using the same method.
Imo passing parameter to server like
page search it's very annoying for a good
user experience.
UPDATE (for the point in the comment)
So a possible way to go
could be get from the server
like 1000 items at once if the user go too close
to the offset (ie it's on the 800 items)
retrieve the next 1000 items from the server
merge cache and so on
it's quite strange not even ng-grid manage pagination
sending parameters to the server
UPDATE
I ended up like:
(function(window, angular, undefined) {
'use strict';
angular.module('my.modal.stream',[])
.provider('Stream', function() {
var apiBaseUrl = null;
this.setBaseUrl = function(url) {
apiBaseUrl = url;
};
this.$get = function($http,$q) {
return {
get: function(id) {
if(apiBaseUrl===null){
throw new Error('You should set a base api url');
}
if(typeof id !== 'number'){
throw new Error('Only integer is allowed');
}
if(id < 1){
throw new Error('Only integer greater than 1 is allowed');
}
var url = apiBaseUrl + '/' + id;
var deferred = $q.defer();
$http.get(url)
.success(function (response) {
deferred.resolve(response);
})
.error(function(data, status, headers, config) {
deferred.reject([]);
});
return deferred.promise;
}
};
};
});
})(window, angular);
(function(window, angular, undefined) {
'use strict';
angular.module('my.mod.pagination',['my.mod.stream'])
.factory('Paginator', function(Stream) {
return function(pageSize) {
var cache =[];
var staticCache =[];
var hasNext = false;
var currentOffset= 0;
var numOfItemsXpage = pageSize;
var numOfItems = 0;
var totPages = 0;
var currentPage = 1;
var end = 0;
var start = 0;
var chunk = 0;
var currentChunk = 1;
var offSetLimit = 0;
var load = function() {
Stream.get(currentChunk).then(function(response){
staticCache = _.union(staticCache,response.data);
cache = _.union(cache,response.data);
chunk = response.chunk;
loadFromCache();
});
};
var loadFromCache= function() {
numOfItems = cache.length;
offSetLimit = (currentPage*numOfItemsXpage)+numOfItemsXpage;
if(offSetLimit > numOfItems){
currentChunk++;
load();
}
hasNext = numOfItems > numOfItemsXpage;
totPages = Math.ceil(numOfItems/numOfItemsXpage);
paginator.items = cache.slice(currentOffset, numOfItemsXpage*currentPage);
start = totPages + 1;
end = totPages+1;
hasNext = numOfItems > (currentPage * numOfItemsXpage);
};
var paginator = {
items : [],
notFilterLabel: '',
hasNext: function() {
return hasNext;
},
hasPrevious: function() {
return currentOffset !== 0;
},
hasFirst: function() {
return currentPage !== 1;
},
hasLast: function() {
return totPages > 2 && currentPage!==totPages;
},
next: function() {
if (this.hasNext()) {
currentPage++;
currentOffset += numOfItemsXpage;
loadFromCache();
}
},
previous: function() {
if(this.hasPrevious()) {
currentPage--;
currentOffset -= numOfItemsXpage;
loadFromCache();
}
},
toPageId:function(num){
currentPage=num;
currentOffset= (num-1) * numOfItemsXpage;
loadFromCache();
},
first:function(){
this.toPageId(1);
},
last:function(){
this.toPageId(totPages);
},
getNumOfItems : function(){
return numOfItems;
},
getCurrentPage: function() {
return currentPage;
},
getEnd: function() {
return end;
},
getStart: function() {
return start;
},
getTotPages: function() {
return totPages;
},
getNumOfItemsXpage:function(){
return numOfItemsXpage;
},
search:function(str){
if(str===this.notFilterLabel){
if(angular.equals(staticCache, cache)){
return;
}
cache = staticCache;
}
else{
cache = staticCache;
cache = _.filter(cache, function(item){ return item.type == str; });
}
currentPage = 1;
currentOffset= 0;
loadFromCache();
}
};
load();
return paginator;
}
});
})(window, angular);
server side with laravel (All the items are cached)
public function tag($page)
{
$service = new ApiTagService(new ApiTagModel());
$items = $service->all();
$numOfItems = count($items);
if($numOfItems > 0){
$length = self::CHUNK;
if($length > $numOfItems){
$length = $numOfItems;
}
$numOfPages = ceil($numOfItems/$length);
if($page > $numOfPages){
$page = $numOfPages;
}
$offSet = ($page - 1) * $length;
$chunk = array_slice($items, $offSet, $length);
return Response::json(array(
'status'=>200,
'pages'=>$numOfPages,
'chunk'=>$length,
'data'=> $chunk
),200);
}
return Response::json(array(
'status'=>200,
'data'=> array()
),200);
}
The only trouble by now is managing filter
I've no idea how to treat filtering :(
In my Angular/WebAPI app I'm struggling with retrieving a specific record by its id.
On the Front-End I have a controller and a data service. The controller calls a method on the data service, and the data service makes $http call to a WebAPI.
In my controller I'm passing the OID of the desired record to the getServiceRequestById method of the data service. Once of my issues is, that the actual value of that OID comes out as :1 instead of just 1.
My other issue is, that when the data service makes a call to WebAPI, the WebAPI perceives the request, as if it caries no ID in it, and passes that request onto its Get() method, instead of Get(int Id).
Here is my Front-End controller:
angular.module('frontEndApp').controller('EditServiceRequestCtrl',['$scope', 'requestsRepository','$routeParams',
function ($scope, requestsRepository,$routeParams) {
console.log("This is EditServiceRequestCtrl ; $routeParams: " + $routeParams);
//First we make a call to the data service, to fetch our ServiceRequest by its OID
//Then, in the callback function, we populate the $scope models below with the data of our retreived ServiceRequest
var getCleanId = function () {
return $routeParams.OID.substring(0, 2)
};
var Id = getCleanId();
//var cleanId = id.substring(0, 2);
console.log('getCleanId Id: ' + Id);
requestsRepository.getServiceRequestById(Id, function (request) {
$scope.OID = request.OID;
$scope.RequestorName = request.RequestorName;
$scope.RequestorBusinessUnit = request.RequestorBusinessUnit;
$scope.CustomerName = request.CustomerName;
$scope.CscContactPerson = request.CscContactPerson;
$scope.IsWbsCodeAvailable = request.IsWbsCodeAvailable;
$scope.SalesforceIdNumber = request.SalesforceIdNumber;
$scope.ProjectCtv = request.ProjectCtv;
$scope.RequestedCompletionDate = request.RequestedCompletionDate;
$scope.ToBeUsedForCloudMigration = request.ToBeUsedForCloudMigration;
$scope.ToBeUsedForDatacenterMove = request.ToBeUsedForDatacenterMove;
$scope.ToBeUsedForServerRefresh = request.toBeUsedForServerRefresh;
$scope.DataRequirements = request.DataRequirements;
$scope.DataProtectionRequirements = request.DataProtectionRequirements;
$scope.ProjectedDataAvailability = request.ProjectedDataAvailability;
$scope.DiscoveryLeadName = request.DiscoveryLeadName;
$scope.SelectedCountries = request.SelectedCountries;
$scope.ManualDiscovery = request.ManualDiscovery;
$scope.AutomatedDiscovery = request.AutomatedDiscovery;
$scope.DataLoadUsingMasterTemplate = request.DataLoadUsingMasterTemplate;
$scope.DataLoadUsingAutomatedInterface = request.DataLoadUsingAutomatedInterface;
$scope.DataLoaderRequiresSitizenship = request.DataLoaderRequiresSitizenship;
$scope.countries = [
{
name: "US", checked: false
},
{
name: "UK", checked: false
},
{
name: "France", checked: false
},
{
name: "Germany", checked: false
},
{
name: "Sweden", checked: false
},
{
name: "Danmark", checked: false
}
];
var list = [];
$scope.checkit = function () {
for (var p in $scope.countries) {
if ($scope.countries[p].checked) {
list.push($scope.countries[p].name);
console.log("selected country: " + $scope.countries[p].name + " " + $scope.ProjectedDataAvailability);
}
} return list;
}
console.log('EditServiceRequestCtrl $scope.RequestorName : ' + $scope.RequestorName);
});
$scope.updateServiceRequest = function () {
var ServiceRequest = {
requestorName: $scope.RequestorName,
requestorBusinessUnit: $scope.RequestorBusinessUnit,
customerName: $scope.CustomerName,
cscContactPerson: $scope.CscContactPerson,
isWbsCodeAvailable: $scope.IsWbsCodeAvailable,
salesforceIdNumber: $scope.SalesforceIdNumber,
projectCtv: $scope.ProjectCtv,
requestedCompletionDate: $scope.RequestedCompletionDate,
projectedDataAvailability: $scope.ProjectedDataAvailability,
toBeUsedForCloudMigration: $scope.ToBeUsedForCloudMigration,
toBeUsedForDatacenterMove: $scope.ToBeUsedForDatacenterMove,
toBeUsedForServerRefresh: $scope.ToBeUsedForServerRefresh,
dataRequirements: $scope.DataRequirements,
dataProtectionRequirements: $scope.DataProtectionRequirements,
selectedCountries:
list.filter(function (itm, i, a) {
return i == a.indexOf(itm);
}).toString(),
projectedDataAvailability: $scope.ProjectedDataAvailability,
discoveryLeadName: $scope.DiscoveryLeadName,
manualDiscovery: $scope.ManualDiscovery,
automatedDiscovery: $scope.AutomatedDiscovery,
dataLoadUsingMasterTemplate: $scope.DataLoadUsingMasterTemplate,
dataLoadUsingAutomatedInterface: $scope.DataLoadUsingAutomatedInterface,
dataLoaderRequiresSitizenship: $scope.DataLoaderRequiresSitizenship
};
requestsRepository.updateServiceRequest(ServiceRequest);
}
}]);
Here is my Front-End data service:
frontEndApp.factory('requestsRepository',function ($http) {
var createServiceRequest = function (ServiceRequest) {
$http(
{
url: 'http://localhost:8080/api/ServiceRequests', method: "POST", data: ServiceRequest,
headers: {
'Content-Type': 'application/json'
}
}).success(function (data, status, headers, config) {
console.log("createServiceRequest Status: " + status);
}).error(function (data, status, headers, config) {
console.log("createServiceRequest FAILURE: " + status + " ServiceRequest: " + ServiceRequest);
});
};
var updateServiceRequest = function (ServiceRequest) {
$http(
{
url: 'http://localhost:8080/api/ServiceRequests', method: "PUT", data: ServiceRequest,
headers: {
'Content-Type': 'application/json'
}
}).success(function (data, status, headers, config) {
console.log("updateServiceRequest Status: " + status);
}).error(function (data, status, headers, config) {
console.log("updatetServiceRequest FAILURE: " + status + " ServiceRequest: " + ServiceRequest);
});
};
var getServiceRequests = function (successCallback) {
$http({
method: 'GET', url: 'http://localhost:8080/api/ServiceRequests'
}).success(function (data, status, headers, config) {
successCallback(data);
}).error(function (data, status, headers, config) {
return status;
});
};
var getServiceRequestById = function (Id,successCallback) {
$http({
method: 'GET', url: 'http://localhost:8080/api/ServiceRequests/' + Id
}).success(function (data, status, headers, config) {
console.log("getServiceRequestById, data: " + data);
successCallback(data);
}).error(function (data, status, headers, config) {
return status;
});
};
return {
createServiceRequest: createServiceRequest, getServiceRequests: getServiceRequests,
updateServiceRequest: updateServiceRequest, getServiceRequestById: getServiceRequestById
};
});
And here is my Back-End WebAPI:
public HttpResponseMessage Get()
{
var requestList = from req in new XPQuery<DummyRequest>(uow) select req;
List<AccountViewServiceRequest> dataList = new List<AccountViewServiceRequest>();
foreach(var item in requestList)
{
AccountViewServiceRequest sr = new AccountViewServiceRequest();
sr.OID = item.Oid;
sr.RequestorName = item.RequestorName;
sr.RequestorBusinessUnit = item.RequestorBusinessUnit;
sr.CustomerName = item.CustomerName;
sr.CscContactPerson = item.CscContactPerson;
sr.IsWbsCodeAvailable = item.IsWbsCodeAvailable;
sr.SalesforceIdNumber = item.SalesforceIdNumber;
sr.ProjectCtv = item.ProjectCtv;
sr.RequestedCompletionDate = item.RequestedCompletionDate;
sr.ToBeUsedForCloudMigration = item.ToBeUsedForCloudMigration;
sr.ToBeUsedForDatacenterMove = item.ToBeUsedForDatacenterMove;
sr.ToBeUsedForServerRefresh = item.ToBeUsedForServerRefresh;
sr.DataRequirements = item.DataRequirements;
sr.SelectedCountries = item.SelectedCountries;
sr.DataProtectionRequirements = item.DataProtectionRequirements;
sr.ProjectedDataAvailability = item.ProjectedDataAvailability;
sr.DiscoveryLeadName = item.DiscoveryLeadName;
sr.ManualDiscovery = item.ManualDiscovery;
sr.AutomatedDiscovery = item.AutomatedDiscovery;
sr.DataLoadUsingMasterTemplate = item.DataLoadUsingMasterTemplate;
sr.DataLoadUsingAutomatedInterface = item.DataLoadUsingAutomatedInterface;
sr.DataLoaderRequiresSitizenship = item.DataLoaderRequiresSitizenship;
dataList.Add(sr);
}
var response = Request.CreateResponse(HttpStatusCode.OK, dataList.ToList());
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;
}
public HttpResponseMessage Get(int Oid)
{
var item = (from req in new XPQuery<DummyRequest>(uow) where req.Oid == Convert.ToInt32(Oid) select req).First();
AccountViewServiceRequest sr = new AccountViewServiceRequest();
sr.OID = item.Oid;
sr.RequestorName = item.RequestorName;
sr.RequestorBusinessUnit = item.RequestorBusinessUnit;
sr.CustomerName = item.CustomerName;
sr.CscContactPerson = item.CscContactPerson;
sr.IsWbsCodeAvailable = item.IsWbsCodeAvailable;
sr.SalesforceIdNumber = item.SalesforceIdNumber;
sr.ProjectCtv = item.ProjectCtv;
sr.RequestedCompletionDate = item.RequestedCompletionDate;
sr.ToBeUsedForCloudMigration = item.ToBeUsedForCloudMigration;
sr.ToBeUsedForDatacenterMove = item.ToBeUsedForDatacenterMove;
sr.ToBeUsedForServerRefresh = item.ToBeUsedForServerRefresh;
sr.DataRequirements = item.DataRequirements;
sr.SelectedCountries = item.SelectedCountries;
sr.DataProtectionRequirements = item.DataProtectionRequirements;
sr.ProjectedDataAvailability = item.ProjectedDataAvailability;
sr.DiscoveryLeadName = item.DiscoveryLeadName;
sr.ManualDiscovery = item.ManualDiscovery;
sr.AutomatedDiscovery = item.AutomatedDiscovery;
sr.DataLoadUsingMasterTemplate = item.DataLoadUsingMasterTemplate;
sr.DataLoadUsingAutomatedInterface = item.DataLoadUsingAutomatedInterface;
sr.DataLoaderRequiresSitizenship = item.DataLoaderRequiresSitizenship;
var response = Request.CreateResponse(HttpStatusCode.OK, sr);
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;
}
Which part should I correct to successfully retrieve a single e record based on its OID?
Since it appears that your first issue is related to this routine:
var getCleanId = function () {
return $routeParams.OID.substring(0, 2)
};
Change the substring starting position to 1 to remove the prepended colon.
var getCleanId = function () {
return $routeParams.OID.substring(1, 2)
};
That in turn should fix the issue with not getting a single record out of the web api. The web api is trying to find a matching function signature in the controller on the web server. The only parameter can't convert to an integer, so it uses the Get() instead of the Get(int Oid).