Angularjs dependency injection of an instantiable class - angularjs

I am trying to learn a little about AngularJS. I have created websites in ASP.NET before so I decided to try to create an AngularJS site with MVC. I downloaded this excellent example:
https://github.com/jph00/AngularTutorial/tree/master/AngularTutorial
I created my own site based upon it but I have a problem with the dependency injection in the AngularJS code.
I created a class called Hotel
public class Hotel
{
public int HotelId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public string Notes { get; set; }
}
In the AngularJS code I have a file called Emp.js
var HotelApp = angular.module('HotelApp', ['ngResource']).
HotelApp.factory('Hotel', function ($resource) {
return $resource('/api/Hotel/:HotelId', { HotelId: '#HotelId' }, { update: { method: 'PUT' } });});
I also have HotelApp declared in the div tag of the page where I need it;
<div ng-app="HotelApp" data-ng-controller="hotelController" class="container">
However when I set breakpoints and jump to them, Hotel is always undefined. The only difference between the GitHub example and my project is that my project uses cshtml (the GitHub example is html).
I have not seen many examples online of dependency injection with AngularJS but those I have seen don't use instantiable classes (as my example has). Is there any example out there of AngularJS like this (dependency injection in an MVC project using a class)?
Edit:this is the Controller class;
{
public class HotelController : ApiController
{
private HotelsContext db = new HotelsContext();
// GET api/<controller>
[HttpGet]
public IEnumerable<Hotel> Get()
{
return db.Hotels.AsEnumerable();
}
// GET api/<controller>/5
public Hotel Get(int id)
{
Hotel hotel = db.Hotels.Find(id);
if (hotel == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return hotel;
}
// POST api/<controller>
public HttpResponseMessage Post(Hotel hotel)
{
if (ModelState.IsValid)
{
db.Hotels.Add(hotel);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, hotel);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = hotel.HotelId }));
return response;
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
// PUT api/<controller>/5
public HttpResponseMessage PutHotel(int id, Hotel hotel)
{
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
if (id != hotel.HotelId)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
db.Entry(hotel).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
// DELETE api/<controller>/5
public HttpResponseMessage Delete(int id)
{
Hotel hotel = db.Hotels.Find(id);
if (hotel == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
db.Hotels.Remove(hotel);
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
return Request.CreateResponse(HttpStatusCode.OK, hotel);
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
The AngularJS controller is;
function hotelController($scope, $http) {
$scope.loading = true;
$scope.addMode = false;
//Used to display the data
$http.get('/api/Hotel/').success(function (data) {
$scope.hotels = data;
$scope.loading = false;
})
.error(function () {
$scope.error = "An Error has occured while loading posts!";
$scope.loading = false;
});
$scope.toggleEdit = function ($scope, $location, $routeParams, Hotel) {
alert("Edit 1");
$scope.action = "Update";
alert("Edit 2");
id = $scope.HotelId;
alert("id is " + id);
// $scope.item = Todo.get({ id: id });
this.hotel.editMode = !this.hotel.editMode;
};
//Used to save a record after edit
$scope.save = function ($scope, $location, $routeParams, Hotel) {
alert("scope item");
alert("Hotel " + Hotel.id);
$scope.item = Hotel.get({ id: id });
alert("scope.item" );
Hotel.update({ id: id }, $scope.item, function () {
// $location.path('/');
alert("id is " + id);
});
};
//Used to add a new record
$scope.add = function () {
$scope.loading = true;
$http.post('/api/Hotel/', this.newhotel).success(function (data) {
alert("Added Successfully!!");
$scope.addMode = false;
$scope.hotels.push(data);
$scope.loading = false;
}).error(function (data) {
$scope.error = "An Error has occured while Adding Friend! " + data;
$scope.loading = false;
});
};
//Used to edit a record
$scope.deletefriend = function () {
$scope.loading = true;
var friendid = this.hotel.FriendId;
$http.delete('/api/Hotel/' + friendid).success(function (data) {
alert("Deleted Successfully!!");
$.each($scope.hotels, function (i) {
if ($scope.hotels[i].FriendId === friendid) {
$scope.hotels.splice(i, 1);
return false;
}
});
$scope.loading = false;
}).error(function (data) {
$scope.error = "An Error has occured while Saving Friend! " + data;
$scope.loading = false;
});
};
}

This has been resolved for me. The problem was the controller function had to be changed to get a reference to the Hotel class.
It was
function hotelController($scope, $http) {
but is now
function hotelController($scope, Hotel) {
If anybody needs further clarification contact me.

You need to define your controller and pass Hotel as a dependency.
DEMO
var HotelApp = angular.module('HotelApp', []);
HotelApp.factory('Hotel', [function() {
return {
run: function() {
alert("run");
}
}
}]);
HotelApp.controller("hotelController", ["$scope", "Hotel",
function($scope, Hotel) {
Hotel.run();
}
]);
Good read on dependency injection in angular.
EDIT:
Remove $scope, $location, $routeParams and Hotel parameters. You need to add those as dependency in your controller like in the example above.
$scope.toggleEdit = function($scope, $location, $routeParams, Hotel) {
alert("Edit 1");
$scope.action = "Update";
alert("Edit 2");
id = $scope.HotelId;
alert("id is " + id);
// $scope.item = Todo.get({ id: id });
this.hotel.editMode = !this.hotel.editMode;
};
//Used to save a record after edit
$scope.save = function($scope, $location, $routeParams, Hotel) {
alert("scope item");
alert("Hotel " + Hotel.id);
$scope.item = Hotel.get({ id: id });
alert("scope.item");
Hotel.update({ id: id }, $scope.item, function() {
// $location.path('/');
alert("id is " + id);
});
};

Related

Uploading files to directory in Jhipster

I'm trying to build the back and front end parts of files uploader in an app built with jhipster 4.0.0, with angularjs.
How can I proceed ? Jhipster is actually giving acess for creating blob type columns with the entities builder , but isn't it a bad idea to store image in the database?
So, how can I build that file uploader ?
Another option you can consider if you don't want to save the file/image as a blob to the database is to create a separate file upload/retrieval service (ours was using MongoDB gridFs as we were dealing with large files) and only send the file id (or file path) of the successfully uploaded file when you save/update the entity.
You can use ng-file-upload to help manage this, note that below code is using angularJS version 1.
<form name="editForm" role="form" novalidate ng-submit="save(userUploadedFile)" show-validation>
<div class="form-group">
<div ng-show="entity.image == null">
<label class="control-label" for="field_file">Image</label>
<input type="file" ngf-select ng-model="userUploadedFile" name="file" id="field_file"
ngf-max-size="8MB" ng-disabled="disableFile" ngf-change="upload($files)" ngf-accept="'image/*'"/>
<button type="button" ng-click="removeUserUploadedFile()" ng-show="userUploadedFile">Remove</button>
</div>
<div ng-show="editForm.file.$invalid">
<p class="help-block" ng-show="editForm.file.$error.maxSize">Error! Image exceeds 8MB file limit</p>
</div>
<my-server-file file-id="entity.image" on-delete="onRemoveServerFile()"/>
</div>
<!-- include submit button etc -->
</form>
The my-server-file directive:
angular.module('myApp')
.directive('myServerFile', function(UrlService, FileService, $log) {
return {
restrict: 'E',
scope: {
fileId: "=fileId",
callbackOnDelete: "&onDelete"
},
template : "<div ng-if='fileId'>" +
"<a ng-if='fileId' ng-href='{{serverFilePath}}' target='_blank' download='{{fileName}}'>{{fileName}}</a>" +
"<button type='button' ng-click='deleteServerFile()' ng-show='fileId'>Remove</button>" +
"</div>",
controller: ['$scope',
function($scope) {
$scope.getFile = function(fileId) {
if(fileId){
$scope.serverFilePath = UrlService.getContextPath() + '/api/file/' + fileId;
FileService.getFileMetaData(fileId).then(function(file){
$scope.fileName = file.name;
});
}
}
$scope.deleteServerFile = function(){
FileService.deleteFile($scope.fileId).then(function() {
$scope.callbackOnDelete();
});
}
}
],
link: function(scope, iElement, iAttrs, ctrl) {
scope.$watch('fileId', function(value) {
scope.getFile(value);
})
}
}
})
Your controller will need to upload the file before it saves.
'use strict';
angular.module('myApp').controller('myAppController',
['$scope', '$stateParams', '$uibModalInstance', 'entity', 'UrlService', 'Upload', '$timeout', 'MyEntity'
function($scope, $stateParams, $uibModalInstance, entity, UrlService, Upload, $timeout, MyEntity) {
$scope.entity = entity;
$scope.load = function(id) {
MyEntity.get({id : id}, function(result) {
$scope.entity = result;
});
};
$scope.onRemoveServerFile = function() {
//Need to remove the file reference from the entity.
$scope.entity.image = null;
if($scope.entity.id){
MyEntity.update($scope.entity);
}
}
$scope.removeUserUploadedFile = function() {
$scope.userUploadedFile = null;
}
var uploadFile = function(file){
file.upload = Upload.upload({
url: UrlService.getContextPath() + '/api/file',
file: file
});
file.upload.then(function (response) {
$timeout(function () {
file.result = response.data;
$scope.entity.image = file.result.fileId;
saveEntity();
});
}, function (response) {
if (response.status > 0)
$scope.errorMsg = response.status + ': ' + response.data;
}, function (evt) {
// Math.min is to fix IE which reports 200% sometimes
file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
});
}
var onSaveSuccess = function (result) {
$scope.isSaving = false;
$scope.$emit('myApp:entityUpdate', result);
$uibModalInstance.close(result);
};
var onSaveError = function (result) {
$scope.isSaving = false;
};
var saveEntity = function() {
$scope.isSaving = true;
if ($scope.entity.id != null) {
MyEntity.update($scope.entity, onSaveSuccess, onSaveError);
} else {
MyEntity.save($scope.entity, onSaveSuccess, onSaveError);
}
};
$scope.save = function (file) {
if(file != null){
uploadFile(file);
}
else {
saveEntity();
}
};
}]);
This does introduce some drawbacks though, when you delete the entity you will need to delete the file separately.
Create a simple FileSerivce to interact with the backend.
angular.module('myApp')
.factory('FileService', function ($http) {
return {
getFile: function(fileId) {
return $http.get('api/file/' + fileId).then(function (response) {
return response.data;
});
},
getFileMetaData: function(fileId) {
return $http.get('api/file/' + fileId + '/metaData').then(function (response) {
return response.data;
});
},
deleteFile: function(fileId) {
return $http.delete('api/file/' + fileId);
}
}
});
And finally your REST controller, here we are delegating to a custom wrapper for GridFs but you could just save it to the file system and return the full path as the id.
#RestController
#RequestMapping("/api/file")
public class FileController {
private final Logger log = LoggerFactory.getLogger(FileController.class);
#Inject
private GridFsService gridFsService;
#RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, String> upload(#RequestParam("file") MultipartFile file)
throws IOException {
GridFSFile storeFile = null;
if (!file.isEmpty()) {
storeFile = gridFsService.storeFile(file);
}
Map<String, String> map = new HashMap<>();
map.put("fileId", storeFile.getId().toString());
return map;
}
#RequestMapping(value="/{fileId}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<InputStreamResource> getFile(
#PathVariable String fileId) throws IOException {
return gridFsService.getFile(fileId).map(f -> new ResponseEntity<> (
new InputStreamResource(f.getInputStream()),
HeaderUtil.createFileContentLengthAndContentTypeHeaders(f.getLength(), f.getContentType()),
HttpStatus.OK
)).orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
#RequestMapping(value="/{fileId}/metaData",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<Map<String, String>> getFileMetaData(
#PathVariable String fileId) throws IOException {
Optional<GridFSDBFile> optFile = gridFsService.getFile(fileId);
if(!optFile.isPresent()){
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
GridFSDBFile file = optFile.get();
Map<String, String> map = new HashMap<>();
map.put("name", file.getFilename());
map.put("contentType", file.getContentType());
map.put("size", String.valueOf(FileUtils.byteCountToDisplaySize(file.getLength())));
return ResponseEntity.ok()
.body(map);
}
#RequestMapping(value="/{fileId}", method = RequestMethod.DELETE)
public void deleteFile(
#PathVariable String fileId) throws IOException {
log.debug("REST request to delete File : {}", fileId);
gridFsService.deleteFile(fileId);
}
}

Where to handle returning data from Angular service?

I try to handle an Angularjs 1 project by using classes, I have created class as the following
angular.module('Models').factory('Project', function (API, $rootScope) {
var Project = function() {
return new Project.fn.init();
}
// instance methods
Project.fn = Project.prototype = {
init: function() {
this.id = null,
this.name = ""
},
setId: function(id) {
this.id = id;
},
setName: function(name) {
this.name = name;
},...
Now I set the obj attr. in the same class as following:
Project.getAll = function(scopeProjects) {
return API.getAll(this).then(function(response) {
var allProjects = response.data.body;
allProjects.forEach(function (project) {
var obj = new Project();
obj.setId(project.id);
obj.setName(project.name);
scopeProjects.push(obj);
})
}, function(error) {
console.log("Fail : ", error);
});
}
my question is where to use my setters?
Do I have to handle this by returning the data to controllers or the way I use here is the best one?

Delay loading data in Angular JS

I have code like this
(function (app) {
app.controller('productListController', productListController)
productListController.$inject = ['$scope', 'apiService', 'notificationService', '$ngBootbox', '$filter'];
function productListController($scope, apiService, notificationService, $ngBootbox, $filter) {
$scope.products = [];
$scope.page = 0;
$scope.pagesCount = 0;
$scope.getProducts = getProducts;
$scope.keyword = '';
$scope.search = search;
$scope.deleteProduct = deleteProduct;
$scope.selectAll = selectAll;
$scope.deleteMultiple = deleteMultiple;
function deleteMultiple() {
var listId = [];
$.each($scope.selected, function (i, item) {
listId.push(item.ID);
});
var config = {
params: {
checkedProducts: JSON.stringify(listId)
}
}
apiService.del('/api/product/deletemulti', config, function (result) {
notificationService.displaySuccess('Deleted successfully ' + result.data + 'record(s).');
search();
}, function (error) {
notificationService.displayError('Can not delete product.');
});
}
$scope.isAll = false;
function selectAll() {
if ($scope.isAll === false) {
angular.forEach($scope.products, function (item) {
item.checked = true;
});
$scope.isAll = true;
} else {
angular.forEach($scope.products, function (item) {
item.checked = false;
});
$scope.isAll = false;
}
}
$scope.$watch("products", function (n, o) {
var checked = $filter("filter")(n, { checked: true });
if (checked.length) {
$scope.selected = checked;
$('#btnDelete').removeAttr('disabled');
} else {
$('#btnDelete').attr('disabled', 'disabled');
}
}, true);
function deleteProduct(id) {
$ngBootbox.confirm('Are you sure to detele?').then(function () {
var config = {
params: {
id: id
}
}
apiService.del('/api/product/delete', config, function () {
notificationService.displaySuccess('The product hase been deleted successfully!');
search();
}, function () {
notificationService.displayError('Can not delete product');
})
});
}
function search() {
getProducts();
}
function getProducts(page) {
page = page || 0;
var config = {
params: {
keyword: $scope.keyword,
page: page,
pageSize: 20
}
}
apiService.get('/api/product/getall', config, function (result) {
if (result.data.TotalCount == 0) {
notificationService.displayWarning('Can not find any record.');
}
$scope.products = result.data.Items;
$scope.page = result.data.Page;
$scope.pagesCount = result.data.TotalPages;
$scope.totalCount = result.data.TotalCount;
}, function () {
console.log('Load product failed.');
});
}
$scope.getProducts();
}
})(angular.module('THTCMS.products'));
So my problem is when i loading data the application take me some time to load data.
I need load data as soon as
Is the any solution for this?
Since you are loading data via api call, there will be a delay. To handle this delay, you should display a loading screen. Once the data is loaded, the loading screen gets hidden and your main screen is visible. You can achieve this using $http interceptors.
See : Showing Spinner GIF during $http request in angular
The api-call is almost certainly causing the delay. Data may be received slowly via the api-call so you could display any sort of loading text/image to notify the use that the data is being loaded.
If u want the data ready at the time when controller inits, u can add a resolve param and pass the api call as a $promise in the route configuration for this route.

Common service for sessionstorage in angularjs

Hi in my application i am setting the values in login controller and getting in all the other js files, other than this how to use a common service for setting storage and getting that storage in required js files
My login controller
app.controller('LoginController',function(loginService, $rootScope,$scope, $http,$location) {
$scope.login = function () {
$scope.log=loginService.getLogin( $scope.emailId , $scope.password).
then(function (response) {
console.log($scope.log);
console.log(response)
if (response.data.LoginVerificationResult.length === 0) {
alert('details are not Available for this emailId');
$scope.error=true;
} else {
$rootScope.name=response.data.LoginVerificationResult[0].UserName;
$scope.abc=response.data.LoginVerificationResult[0].UserType
console.log($scope.abc+"from.......");
sessionStorage.setItem("EmaiId",$scope.emailId);
sessionStorage.setItem("User Id",response.data.LoginVerificationResult[0].UserID);
sessionStorage.setItem("UserName",response.data.LoginVerificationResult[0].UserName);
sessionStorage.setItem("UserType",response.data.LoginVerificationResult[0].UserType);
$scope.UserType = sessionStorage.getItem("UserType");
console.log($scope.UserType +"from login controller")
$location.path('/dashboard')
}
});
};
});
My changepassword file
app.controller("ChangePwdController", function($scope, $http, $location,
BaseUrl, changePwdService) {
//$scope.roleId = sessionStorage.getItem("Role ID");
/* $scope.UserType = sessionStorage.getItem("UserType");*/
$scope.username = sessionStorage.getItem("UserName");
$scope.userType = sessionStorage.getItem("UserType");
$scope.EmpName=sessionStorage.getItem("EmpName");
$scope.patientName=sessionStorage.getItem("PatientName")
$scope.changePwd = function() {
$scope.emailAddress = sessionStorage.getItem("EmaiId");
console.log($scope.emailAddress)
var data = {
'emailAddress' : $scope.emailAddress,
'currentPassword' : $scope.opassword,
'newPassword' : $scope.npassword
};
console.log("Hi")
$scope.pwd=changePwdService.postChangePwd(data).success(
function(resp) {
$scope.PostDataResponse = data;
console.log($scope.pwd)
console.log($scope.PostDataResponse);
if (resp.ResetPasswordResult === true) {
alert("Successfully changed");
console.log("success")
$location.path('/dashboard');
} else {
console.log("fail")
alert("Enter valid current password")
}
})
}
})
Is there any alternative way to set and get in one file
There are ways in which you can achieve the same. Please refer this here.

AngularJS $http.get in MVC5 Areas

I have an Area named Employer in MVC5 and in the root a folder named app that contains a folder named list. In list folder I created js files and as a service factory I user this code :
angSalaryApp.factory('listService', ["$http",
function ($http) {
return {
newList: newList
};
function newList() {
return $http.get("Areas/Employer/List/newlist");
}
return {
userLists: userLists
};
function userLists() {
return $http.get("Areas/Employer/List/getlists");
}
}
]);
but newlist and userlists actions aren't called and my controller variables are undefined. it's my controller code :
angSalaryApp.controller('listController',
function ListController($scope, listService) {
$scope.list = listService.newList;
$scope.userlist = [];
$scope.count = 0;
$scope.submitForm = function () {
};
$scope.loadLists = function () {
$scope.userlist = listService.userLists;
$scope.d = "ffdgdfg";
};
$scope.updateName = function (newtitle) {
$scope.list.Name = newtitle;
};
});
You need to restructure your factory like this:
angSalaryApp.factory('listService', ["$http",
function ($http) {
return {
newList: newList,
userLists: userLists
};
function newList() {
return $http.get("Areas/Employer/List/newlist");
}
function userLists() {
return $http.get("Areas/Employer/List/getlists");
}
}
]);
...otherwise userLists will be private.
Have you tried to move the route initialization to the Area registration?
using System.Web.Mvc;
namespace MyAreaTest
{
public class MyAreaRegistration : AreaRegistration
{
public override string AreaName
{
get { return "MyArea"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Area_default",
"MyArea/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}

Resources