Creating custom service in Angular using MeanJS - angularjs

Still very new to MeanJS and Angular, but am trying to get a repeater to use a custom node service that i created
Here is the Angular Template
<section data-ng-controller="AppController">
<section data-ng-controller="GroupsController" data-ng-init="findMyItems()">
<div class="page-header">
<h1>My Groups</h1>
</div>
<div class="list-group">
<a data-ng-repeat="group in groups" data-ng-href="#!/groups/{{group._id}}" class="list-group-item">
<small class="pull-right" data-ng-bind="group.shortId"></small>
<h4 class="list-group-item-heading" data-ng-bind="group.name"></h4>
<small class="list-group-item-text">
Posted on
<span data-ng-bind="group.created | date:'medium'"></span>
by
<span data-ng-bind="group.user.displayName"></span>
</small>
</a>
</div>
<div class="alert alert-warning text-center" data-ng-hide="!groups.$resolved || groups.length">
No Groups yet, why don't you create one?
</div>
</section>
</section>
Here is an array of JSON objects returned from localhost:3000/users/me/groups
[
{
_id: "5407dd31594e810000af4fa0",
user: "5407c78f9ef3025bbf0440f7",
description: "Activating....",
__v: 0,
projects: [ ],
created: "2014-09-04T03:32:01.825Z",
shortId: "bkXtE746M",
name: "Wonder Twins"
},
{
_id: "5407dc49a34a610000af6896",
user: "5407c78f9ef3025bbf0440f7",
description: "Loved watching this one",
__v: 0,
projects: [ ],
created: "2014-09-04T03:28:09.480Z",
shortId: "WJejxZorTz",
name: "Fantastic Four"
},
{
_id: "5407d71839c7de000008cf6b",
user: "5407c78f9ef3025bbf0440f7",
description: "Great group",
__v: 0,
projects: [ ],
created: "2014-09-04T03:06:00.098Z",
shortId: "ZJfKDyN6f",
name: "Leaders of the New School"
}
]
Controller
'use strict';
// Groups controller
angular.module('groups').controller('GroupsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Groups', 'GroupsAPI',
function($scope, $stateParams, $location, Authentication, Groups, GroupsAPI ) {
$scope.authentication = Authentication;
$scope.findMyItems = function() {
GroupsAPI.getGroupsByCurrentUser()
.success(function (groups) {
$scope.groups = groups;
})
.error(function (error) {
$scope.status = 'Unable to load group data: ' + error.message;
});
};
}
]);
I'm not exactly sure what the service is doing in MeanJS
'use strict';
//Groups service used to communicate Groups REST endpoints
angular.module('groups').factory('Groups', ['$resource',
function($resource) {
return $resource('groups/:groupId', { groupId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
]);
What I'd like to do is something like to do is something like bellow, but not sure if there is a better way
'use strict';
//Groups service used to communicate Groups REST endpoints
angular.module('groups').factory('Groups', ['$resource',
function($resource) {
return $resource('groups/:groupId', { groupId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
]);
angular.module('groups')
.factory('GroupsAPI', ['$http', function($http) {
var GroupsAPI = {};
GroupsAPI.getGroupsByCurrentUser = function () {
return $http.get('users/me/groups');
};
return GroupsAPI;
}]);
Is there a better way of doing this the MeanJS way?

It's been a long time since you posted this, so you likely figured out a solution already, but for the sake of future readers I'll toss an answer in here.
If I'm understanding what you're trying to do, it looks like you are trying to create a custom factory that functions similar to the existing Groups factory (the one you mentioned you didn't know what it was doing). That's what I'll be answering...
To begin with, you'll want to read the Angular documentation on $resource: https://docs.angularjs.org/api/ngResource/service/$resource. This is what makes the Groups factory work.
To summarize, Angular's $resource allows you to make AJAX requests very easily, by allowing you to create a variable in your controller which has access to REST functions. So basically, you would do something like this:
// Groups controller
angular.module('groups').controller('GroupsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Groups', 'GroupsAPI',
function($scope, $stateParams, $location, Authentication, Groups, GroupsAPI ) {
$scope.authentication = Authentication;
// Since you've added 'Groups' as a dependency, you can now use this "resource" in a new variable.
var groups = new Groups({
// Set any object data you need here, or leave empty.
});
// Now that you have a new instance of your 'Groups' resource (i.e. 'groups'), you can use standard REST calls.
groups.get({
user: currentUser
}, function(results) {
// Do something with results here, e.g.
if(results) {
$scope.groups = results;
} else {
$scope.status = 'Unable to load group data.';
}
});
]);
Note: I haven't tested this code, but this is the idea.

Related

How to post file and data with AngularJS with MEAN stack

I went through hundreds of pages for several days without success and here is my problem.
I use the MEAN stack and at this point I have a simple form that works very well to save a "name" field to a MongoDB collection. Now, I would like, client-side, add an image upload and, on form submit, store the image on my server and finally save the "name" field and the image path to the MongoDB collection.
AngularJS side, I tried using ng-file-upload with multer server-side. I have done well to operate for the upload of the file but only that. But after hundreds of tests, I despair. Here is an extract of my original code without file upload.
Server side
sections.server.model
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var SectionSchema = new Schema({
name: {
type: String,
default: '',
trim: true,
required: true,
unique: true
},
image: {
type: String,
default: ''
}
});
mongoose.model('Section', SectionSchema);
sections.server.controller
exports.create = function (req, res) {
var section = new Section(req.body);
section.save(function (err) {
if (err) {
return res.status(400).send({
message: getErrorMessage(err)
});
} else {
res.json(section);
}
});
};
sections.server.routes
var sections = require('../../app/controllers/sections.server.controller');
module.exports = function (app) {
app.route('/api/sections')
.post(sections.create);
};
Client side
sections.client.module
'use strict';
var sections = angular.module('sections', []);
sections.client.controller
'use strict';
angular.module('sections')
.controller('SectionsController',
['$scope', '$routeParams', '$location', 'Sections'
function ($scope, $routeParams, $location, Sections) {
$scope.create = function () {
var section = new Sections({
name: this.name
});
section.$save(function (response) {
$location.path('sections/' + response._id);
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
};
}]);
sections.client.routes
angular.module('sections').config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/sections', {
controller: 'SectionsController',
templateUrl: 'sections/views/list-sections.client.view.html'
})
.when('/sections/create', {
controller: 'SectionsController',
templateUrl: 'sections/views/create-section.client.view.html'
})
.otherwise({
redirectTo: '/'
});
}]);
sections.client.service
'use strict';
angular.module('sections').factory('Sections', ['$resource', function ($resource) {
return $resource('api/sections/:sectionId', {
sectionId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}]);
create-section.client.view
<section>
<h1>New Article</h1>
<form data-ng-submit="create()" novalidate>
<div>
<label for="name">Nom du rayon</label>
<div>
<input type="text" data-ng-model="name" id="name" placeholder="Name" required>
</div>
</div>
<div>
<input type="submit">
</div>
<div data-ng-show="error"><strong data-ng-bind="error"></strong></div>
</form>
</section>
Now, from this can anyone help me to add the image upload in the form and then save the field name and the image path in MongoDB.
Note that I want to reuse the upload mecanism in other forms of my app.
I had the idea of switching a generic middleware function in the road-side server wich call multer and return the image path to my sections.create function for MongoDB storing, something like that :
module.exports = function (app) {
app.route('/api/sections')
.post(uploads.upload, sections.create);
But I've never managed to pass the file in the POST from AngularJS request.
Thank you so much for all your ideas, your help and possibly an example of code that works.

get allDocs from service and controller using pouchdb

i have problem how to get data from service and controller. now i want implement CRUD into my web apps.
this is my service.
application.service('Arrears', [
function()
{
var db = new PouchDB('localhost:5984/arrears');
return {
allDocs: function (startKey, endKey, desc) {
db.allDocs({startkey: startKey, endkey: endKey, descending: desc})
.then(function (result) {
console.log(result, 'Results from allDocs');
return result;
})
},
}
}
]);
this is my controller.
application.controller('ArrearsManagementAllController', ['$location', '$mdSidenav', '$scope', 'Arrears',
function($location, $mdSidenav, $scope, Arrears)
{
$scope.items= Arrears.allDocs();
}
]);
and my html like this.
<md-list-item md-virtual-repeat="i in items | orderBy:'status'" ng-click="read(id)">
<b md-highlight-flags="gi">
Status :</b> {{i.status}}
<b md-highlight-text="query.$" style="color:blue"
md-highlight-flags="gi">
{{i.owner_name}}
({{i.owner_id}})
</b>
<p class="md-caption"
md-highlight-text="query.$">
{{i.address}}
</p>
<p class="md-caption"
md-highlight-text="query.$">
{{i.house_no}} - Floor {{i.floor}} -, Lot {{i.lot}} -, Block {{i.block}} - {{i.locality}}
</p>
i'm new with angularjs and pouchdb. please help me.
The issue is that allDocs() doens't return a list of documents; it returns a promise for a list of documents. Check out this post on promises for an overview, but basically you will need to do:
application.service('Arrears', [
function()
{
var db = new PouchDB('localhost:5984/arrears');
return {
allDocs: function (startKey, endKey, desc) {
return db.allDocs({startkey: startKey, endkey: endKey, descending: desc, include_docs: true})
},
}
}
]);
application.controller('ArrearsManagementAllController', ['$location', '$mdSidenav', '$scope', 'Arrears',
function($location, $mdSidenav, $scope, Arrears)
{
$scope.items = [];
Arrears.allDocs().then(function (res) {
$scope.items = res.rows.map(function (row) {
return row.doc;
});
}).catch(console.log.bind(console));
}
Hope that helps!

Cordova: Data that is filled inside array could not populate on page

I am not able to populate data filled inside the array.
My main controller front is this:
<body ng-controller="MainCtrl"> // MainCtrl controller
<ion-nav-view animation="slide-left-right"></ion-nav-view>
<script src="js/jquery-2.1.1.min.js"></script>
<script src="js/owl.carousel.min.js"></script>
</body>
the MainCtrl initially contain nothing like this:
.controller('MainCtrl', function($scope, $ionicSideMenuDelegate, $ionicPopover, $state, $timeout) {
$scope.users = [];
$scope.devices = [];
})
Initially when i do login the controller named intro is getting called that controller calls rest & validate user & on successfully validating it does following:
.success(function(data, status, headers, config) {
if (data.alert === 'SUCCESS'){
var UserData = data.userdata;
var Username = UserData.personal_information.first_name+" "+UserData.personal_information.last_name;
var Email = UserData.username;
var LastLogin = new Date(UserData.last_visited * 1000);
$scope.users = [{ username: Username, email: Email, location: true, id: null, avatar: 'img/men.jpg', enabled: 'true', lastLogin: LastLogin}];
if(data.ownteam == true) {
$.each(data.ownteamdata, function( index, value ){
var TeamId = value.team_id;
var TeamName = value.team_name;
var Status = value.role;
var surveyArray = {id : TeamId, name :TeamName, icon: 'ion-document-text', status : Status, color : Color};
$scope.devices.push(surveyArray);
});
}
now when i console the array it shows me the data inserted.
then i move to dashboard page where the data of devices array need to be polupated & shown like:
<div ng-repeat="device in devices | filter: { featured: true}">
<div class="padding-horizontal">
<div class="item item-icon-left" on-tap="deviceTap('router.device', device)">
<i class="icon" ng-class="device.icon"></i>
{{ device.name }}
<span class="badge" ng-class="device.color">
{{ device.status }}
</span>
</div>
</div>
</div>
but it is not showing the data to me in the page??? is there something i m missing?
You're trying to filter the devices where featured = true
<div ng-repeat="device in devices | filter: { featured: true}">
but you don't seem to have that element in your object:
var surveyArray = {
id : TeamId,
name :TeamName,
icon: 'ion-document-text',
status : Status,
color : Color
};
Another problems could be the fact that you're maybe - trying to access the array from 2 different controllers.
I would suggest to check your console in chrome (F12) and use some sort of debug.
UPDATE:
One approach if you want to share data between controllers is to use a shared service, like a session, so you can move of the login for the login and validation there (clean controllers).
You can have a look at this plunker.
In app.services.js you will find a service called userAccountService.
(function () {
'use strict';
var services = angular
.module('app.services', [])
.factory('userAccountService', userAccountService);
userAccountService.$inject = ['$q'];
function userAccountService($q) {
var service = {
users: [],
devices: [],
logIn: logIn,
};
return (service);
function logIn(username, password)
{
var deferred = $q.defer();
this.users.push({username: username});
this.devices = [{name: 'android'}, {name: 'iphone'}];
deferred.resolve({users: this.users, devices: this.devices });
return deferred.promise;
}
};
})();
It will be responsible for the log-in an for sharing data between controllers ... and other modules. It is a singleton.
This service contains 2 arrays: users and devices:
var service = {
users: [],
devices: [],
logIn: logIn
};
The login method will, presumably, authenticate the user through an http call and will populate the shared members: users and devices.
(I've used promises there to match your $http call).
Now you can have a look at the app.controller.js file where my controllers are defined.
They depend on userAccountService.
view1Controller is the starting point and it is in charge for the login:
$scope.login = function()
{
userAccountService.logIn('username', 'password')
.then(function(result){
$scope.users = result.users,
$scope.devices = result.devices
})
.catch(function(reason){
console.log(reason);
});
$state.go('view2');
}
if the login is successful it will populate the two local members to be displayed in the page.
<div ng-repeat="device in devices">
<div class="padding-horizontal">
<div class="item item-icon-left">
{{ device.name }}
</span>
</div>
</div>
</div>
Same thing happens with view2. Now we don't need to login again; we can simply read the shared member of our service:
.controller('view2Controller', function($scope, userAccountService) {
$scope.users = [];
$scope.devices = [];
function init()
{
$scope.users = userAccountService.users;
$scope.devices = userAccountService.devices;
}
init();
})

how to pass global variable in view to controller angularjs

I'm tring to send backend by ejs to the frontend , controller of angularjs
app.js
i pass data to view/indexcontens.
var users = [
{
name: 'john',
email: 'john#email.com'
},
{
name: 'peter',
email: 'peter#email.com'
},
{
name: 'max',
email: 'max#email.com'
}
];
app.get('/partials/indexContents.html', function(req, res) {
res.render('partials/indexContents', {users:users})
});
app.get('/partials/about.html', function(req, res) {
res.render('partials/about')
});
views/partials/indexContents
i made it global variable.
<div>
<h3>home</h3>
<p>wecome to my blog. I hope you enjoy the content!</p>
<ul>
<li ng-repeat="post in blogposts">{{post}}</li>
</ul>
</div>
<script>
users = "<%=abc=users[0].name%>";
</script>
public/js/contollers.js trying to get the global variable
var app= angular.module('blog',['ngRoute']);
app.config(function($routeProvider) {
//set up routes
$routeProvider
.when('/home',{
templateUrl:'partials/indexContents.html',
controller:'SimpleController'
})
.when('/about',{
templateUrl:'partials/about.html',
controller:'AboutController'
})
.otherwise({
redirectTo:'/'
});
});
app.controller('SimpleController', function($scope){
$scope.blogposts=[
'blog post1',
'blog post2',
window.users
];
});
app.controller('AboutController', function($scope){
$scope.name="graum";
$scope.bio="i just made it";
});
but it only display blank instead of 'john'.
Please give me a solution, thank you
Why dont you use $resource to get the name from server? I know this is not the best option and certainly not what you are looking for but this way it works for sure.
however you can try this too
<script>
(function() {users = "<% users[0].name%>";})();
</script>

Inconsistent behavior in AngularJS views populated with Jaydata

I am attempting to build a proof of concept application using AngularJS and Jaydata. I am loosely following the MVC pattern on the AngularJS home page (http://angularjs.org/) under "Wire up a Backend". Instead of Firebase, I'm using WebSQL via Jaydata providers.
I have a WebSQL database called InspecTechDB with two tables, Organizations and Customers. There is a parent/child relationship between the two on OrganizationID. This is from my model:
$data.Entity.extend('Customer', {
'CustomerID': { 'key': true, 'type': 'Edm.Guid', 'nullable': false },
'OrganizationID': { 'type': 'Edm.Guid', 'nullable': false, 'required': true },
'CustomerName': { 'type': 'Edm.String' },
'Organization': { 'type': 'Organization', 'inverseProperty': '$$unbound' }
});
$data.Entity.extend('Organization', {
'OrganizationID': { 'key': true, 'type': 'Edm.Guid', 'nullable': false, 'required': true },
'OrganizationName': { 'type': 'Edm.String' },
'Customers': { 'type': 'Array', 'elementType': 'Customer', 'inverseProperty': '$$unbound' }
});
$data.EntityContext.extend('InspecTechDB', {
'Customers': { type: $data.EntitySet, elementType: Customer },
'Organizations': { type: $data.EntitySet, elementType: Organization }
});
I have 3 template views: OrganizationIndex.html, CustomerIndex.html, and CustomerEdit.html. The CustomerEdit.html is the one I'm having issues with:
<form name="myForm">
<div class="form-group">
<label>OrganizationID</label>
<input type="text" class="form-control" placeholder="OrganizationID" name="OrganizationID" ng-model="customer.OrganizationID" required>
<span ng-show="myForm.name.$error.required" class="help-inline">
Required
</span>
</div>
<div class="form-group" ng-class="{error: myForm.name.$invalid}">
<label>Name</label>
<input type="text" class="form-control" name="CustomerName" ng-model="customer.CustomerName" required>
<span ng-show="myForm.name.$error.required" class="help-inline">
Required
</span>
</div>
</form>
I've included my entire js file here:
var app = angular.module('AngularJaydataApp', ['ngRoute', 'jaydata']);
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
controller: 'OrganizationIndex',
templateUrl: 'OrganizationIndex.html'
})
.when('/CustomerIndex/:id', {
controller: 'CustomerIndex',
templateUrl: 'CustomerIndex.html'
})
.when('/CustomerEdit/:id', {
controller: 'CustomerEdit',
templateUrl: 'CustomerEdit.html'
})
.otherwise({
redirectTo: '/'
});
});
var localDB = new InspecTechDB({
name: 'local',
databaseName: 'InspecTech'
});
app.controller('OrganizationIndex', function ($scope, $data){
//wait until the localDB is ready, then get the Organizations
$.when(localDB.onReady())
.then(function () {
$scope.inspectechdb = localDB;
$scope.organizations = localDB.Organizations.toLiveArray();
});
});
app.controller('CustomerIndex', function ($scope, $data, $routeParams) {
$.when(localDB.onReady())
.then(function () {
$scope.inspectechdb = localDB;
$scope.Customers = $scope.inspectechdb
.Customers
.filter('OrganizationID', '==', $routeParams.id)
.toLiveArray();
});
});
app.controller('CustomerEdit', function ($scope, $data, $routeParams) {
var customerID = $routeParams.id;
$.when(localDB.onReady())
.then(function () {
$scope.inspectechdb = localDB;
$scope.inspectechdb.Customers.single(function (customer) {
return customer.CustomerID == this.Id;
},
{Id: customerID},
function (customer) {
$scope.customer = customer;
console.dir(customer);
});
});
console.log('this entry s/b after the customer console entry');
});
I can successfully navigate to each of the views and populate the OrganziationList.html template from my database as shown in the above code. I've set the Organization list up so that when I click the Organization entry on my view then the CustomerIndex.html view is loaded and bound to my customer list. This works fine. I've also set it up so that when I click a customer entry on the CustomerIndex view then the CustomerEdit.html view is loaded and here is where I get lost. The view appears just fine, but the form is not bound when the view is loaded, and I understand why (I think). It seems to be b/c angular is binding the form before my $scope.customer is populated. Evidence of this is the console log:
this entry s/b after the customer console entry bind.js:68
Customer
My question is this: Why do the OrganzationList and CustomerList views populate correctly and the CustomerEdit form does not and what can be done about it?
UPDATE
For anyone interested, I made it work by modifying the CustomerEdit controller per the accepted answer:
app.controller('CustomerEdit', function ($scope, $data, $routeParams) {
var customerID = $routeParams.id;
$.when(localDB.onReady())
.then(function () {
$scope.inspectechdb = localDB;
$scope.inspectechdb.Customers.single(function (customer) {
return customer.CustomerID == this.Id;
},
{ Id: customerID },
function (customer) {
$scope.$apply(function () {
$scope.customer = customer;
});
});
});
});
Angular has no idea that it should update the form. When you call tolivearray jaydata manages this for you. Calling single does not.
One way of solving it is that you call apply yourself when you updated the scope.
A better way would be to pass the entity instead of loading it, since it's already loaded.

Resources