I've a AngularJs controller that gets a list of categories from ASP.NET MVC controller. It works just fine and here is the below code:
productApp.controller('categoryController', function ($scope, categoryService) { //The controller here
$scope.Categories = null;
categoryService.GetCategories().then(function (d) {
$scope.Categories = d.data;
}, function () {
alert('Failed');
});
});
productApp.factory('categoryService', function ($http) { //The product service
var factory = {};
factory.GetCategories = function () {
return $http.get('/Product/GetCategories'); //The ASP.NET MVC controlled defined
}
return factory;
});
I am trying to convert it to the following passing the service as a controller parameter but it doesn't work:
(function () {
'use strict';
angular
.module('productApp', ['ngMessages'])
.controller('categoryController', categoryController);
categoryController.$inject = ['$scope', 'Products'];
function categoryController($scope, categoryService) {
$scope.Categories = null;
categoryService.GetCategories().then(function (d) {
$scope.Categories = d.data;
}, function () {
alert('Failed');
});
}
productApp.factory('categoryService', function ($http) { //The product service
var factory = {};
factory.GetCategories = function () {
return $http.get('/Product/GetCategories'); //The ASP.NET MVC controlled defined
}
return factory;
});
})();
My requirement is to get all the controller united as follows:
angular
.module('productApp')
.controller('categoryController', categoryController)
.controller('productController', productController);
I believe, I am close enough and missing something here. I would expect some suggestions to implement it in the correct way. Thanks.
Update 1 - The below code works almost but it doesn't bind the DropDownList with category data: But using alert method, it returns [Object][Object] that means it gets categories from database
(function () {
'use strict';
angular
.module('productApp', [])
.controller('categoryController', categoryController)
.factory('categoryService', categoryService);
categoryController.$inject = ['$scope', 'categoryService'];
function categoryController($scope, categoryService) {
$scope.Categories = null;
categoryService.GetCategories().then(function (d) {
$scope.Categories = "Service: " + d.data + ", Controller: categoryController";
alert(d.data); //Here it alert [Object][Object]
}, function () {
alert('Failed');
});
}
function categoryService($http) {
var factory = {};
factory.GetCategories = function () {
return $http.get('/Product/GetCategories');
}
return factory;
};
})();
In the view:
<div ng-app="productApp" ng-controller="categoryController">
<select ng-model="saveProducts.ParentId">
<option value="">----Please Select Category----</option>
<option ng-repeat="m in Categories" value="{{ m.CategoryId }}">{{ m.Category }}</option>
</select>
</div>
#user8512043 Here is a JSFiddle with the working code: http://jsfiddle.net/luisperezphd/2fvwz6wp/
(function () {
'use strict';
angular
.module('productApp', [])
.controller('categoryController', categoryController)
.factory('categoryService', categoryService);
categoryController.$inject = ['$scope', 'categoryService'];
function categoryController($scope, categoryService) {
$scope.Categories = null;
categoryService.GetCategories().then(function (d) {
$scope.Categories = d.data;
}, function () {
alert('Failed');
});
}
function categoryService($http, $q) {
var factory = {};
factory.GetCategories = function () {
//return $http.get('/Product/GetCategories');
return $q.when({ data: [
{ CategoryId: 1, Category: "Category 1" },
{ CategoryId: 10, Category: "Category 2" },
{ CategoryId: 20, Category: "Category 3" }
]});
}
return factory;
};
})();
Note that it looks like code was fine. The drop down wasn't working because you assigned a string to the scope variable instead of an array.
One technique to resolve issue like that is to make it as visual as you can. For example use an ng-repeat on a instead of an .
Also in general if you are going to ask for help on StackOverflow you are going to get a lot more responses if you create a JSFiddle or Plnkr with your sample code.
Finally if you are going to do that mock the server calls. This will allow the person who wants to answer to do some quick experiments.
Check this code
(function () {
'use strict';
angular
.module('productApp',[])
.controller('categoryController', categoryController)
.controller('productController', productController)
.factory('categoryService', categoryService);
function categoryController($scope, categoryService) {
$scope.data = "Service: "+categoryService.serviceName+", Controller: categoryController";
};
function productController($scope, categoryService) {
$scope.data = "Service: "+categoryService.serviceName+", Controller: productController";
};
function categoryService() {
return {serviceName: "categoryService"};
};})();
Related
I'm testing the communication of angular and SQLite. I need to get the ID and NAME of the selected company from database when the User access the page. I'm using the ion-autcomplete to select the company in the CRUD page.
Service: sqlite.js
(function () {
'use strict';
angular
.module('Test')
.service('$sqliteService', $sqliteService);
$sqliteService.$inject = ['$q', '$cordovaSQLite'];
function $sqliteService($q, $cordovaSQLite) {
var self = this;
var _db;
self.db = function () {
if (!_db) {
if (window.sqlitePlugin !== undefined) {
_db = window.sqlitePlugin.openDatabase({ name: "my.db", location: 2, createFromLocation: 1 });
} else {
// For debugging in the browser
_db = window.openDatabase("my.db", "1", "Database", 200000);
}
}
return _db;
};
self.getFirstItem = function (query, parameters) {
var deferred = $q.defer();
self.executeSql(query, parameters).then(function (res) {
if (res.rows.length > 0)
return deferred.resolve(res.rows.item(0));
else
return deferred.reject("There aren't items matching");
}, function (err) {
return deferred.reject(err);
});
return deferred.promise;
};
}
})();
Factory: CompanyService.js
(function () {
'use strict';
angular
.module('Test')
.factory('CompanyService', CompanyService);
CompanyService.$inject = ['$q', '$sqliteService'];
function CompanyService($q, $sqliteService) {
return {
getId: function (Id) {
var query = "Select * FROM Company WHERE ID = ?";
var values = [Id];
return $q.when($sqliteService.getFirstItem(query, values));
}
};
}
})();
Controller: CompanyController.js
(function() {
'use strict';
angular
.module('Test')
.controller('CompanyEditController', CompanyEditController);
CompanyEditController.$inject = ['$scope', '$q', '$stateParams', '$state', '$cordovaCamera', '$cordovaImagePicker', '$ionicPopup', 'CompanyService'];
function OcorrenciaEditController($scope, $q, $stateParams , $state, $cordovaCamera, $cordovaImagePicker, $ionicPopup, CompanyService) {
var vm = $scope;
vm.modelToItemMethod = function (modelValue) {
var d = $q.defer();
CompanyService.getId(modelValue)
.then(function(data) {
console.log('My first promise succeeded', JSON.stringify(data));
$q.resolve(data);
}, function(error) {
console.log('My first promise failed', error.message);
});
return d.promise;
};
})();
Company.html
<input ion-autocomplete ng-model="company.IdCompany" type="text" name="fieldEmpresa" placeholder="Empresa" readonly="readonly" class="ion-autocomplete" autocomplete="off" max-selected-items="1" required
item-value-key="Id"
item-view-value-key="CompanyName"
items-method="getTestItems(query)"
cancel-label="Cancel"
items-removed-method="itemsRemoved()"
loader-icon="spinner"
external-model="company"
model-to-item-method="modelToItemMethod(modelValue)"/>
I don't undestand why I need to use de "$q.defer" inside the controller if i'm using inside de Factory and Service. If I don't use, controller can't return the value to ion-aucomplete. Am i missing something? Or the code is right?
You are binding this method to auto complete; as ajax call is asynchronous, you gotta return a primise. Thats the reason why you ended up using $q.defer.
If you dont want to use $q, then instead of using $q.defer , you can just do return CompanyService.getId(modalValue); in your VM.modelToItemMethod which inturn returns a deferred object.
I am trying to implement ng-tags-input to work within my website, so basically people need to input some tags by choosing tag(s) from a list of available tags persisted on database
server:
exports.list = function(req, res) {
var query = req.query;
mongoose.set('debug', true);
Tag
.find({
'text': new RegExp(query.text, 'i')
})
.sort({
created: -1
})
.select('text')
.exec(function(err, tags) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
console.log('Tags: ', tags);
res.json(tags);
}
});
};
angular controller:
(function() {
'use strict';
angular
.module('contests')
.controller('ContestsAddController', ContestsAddController);
ContestsAddController.$inject = [
'$scope',
'$state',
'$location',
'Tag'
];
function ContestsAddController(
$scope,
$state,
$location,
Tag
) {
var vm = this;
/** Properties */
vm.tags = [];
/** Methods */
vm.loadTags = loadTags;
function loadTags(query) {
return Tag.load();
}
}
}());
view:
<div class="form-group">
<label class="col-md-3 control-label">With tags </label>
<div class="col-md-9">
<tags-input ng-model="vm.tags" add-from-autocomplete-only="true">
<auto-complete source="vm.loadTags($query)" debounce-delay="500" load-on-empty="true"></auto-complete>
</tags-input>
</div>
</div>
angular service:
(function() {
'use strict';
angular
.module('tags')
.factory('Tag', Tag);
Tag.$inject = [
'$http',
'$q',
'$timeout',
'Authentication',
'Shuttle',
'CONST'
];
function Tag(
$http,
$q,
$timeout,
Authentication,
Shuttle,
CONST
) {
var service = {
getTags: getTags,
load: load
};
var _this = this;
return service;
// SCOPE FUNCTIONS
function getTags(query) {
return Shuttle.get(CONST.EP_TAGS, query, {}, 1000, {
Authorization: 'JWT ' + Authentication.token
});
}
function load() {
var deferred = $q.defer();
deferred.resolve(this.getTags({}));
return deferred.promise;
}
}
}());
Tag.load() response
[
{
"_id":"579ecc5fca552b6e89094415",
"text":"Comedian"
},
{
"_id":"579ecc5aca552b6e89094414",
"text":"Cardist"
},
{
"_id":"579ecc56ca552b6e89094413",
"text":"Magician"
},
{
"_id":"579ecc4bca552b6e89094412",
"text":"Actress"
},
{
"_id":"579ecc47ca552b6e89094411",
"text":"Actor"
},
{
"_id":"579ecbecca552b6e89094410",
"text":"Bassist"
},
{
"_id":"579ecbdfca552b6e8909440f",
"text":"Guitarist"
},
{
"_id":"579ecbd9ca552b6e8909440e",
"text":"Singer"
},
{
"_id":"579ecbc6ca552b6e8909440d",
"text":"Dancer"
}
]
The problems that i am facing is that when i typed 3 letters (which correctly triggered Tag.load() as expected, and returning above's response)
it doesn't show any auto complete or tag suggestions
it's immediately putting that 3 letters as a tag (picture below)
the console.log(vm.tags); is not including the whole Tag object, just the text key value pair
is there something i missed?
i am using angular 1.5.0
UPDATE
I have added a plunker although with some modifications, but it is working just fine there, though it still doesn't work in my app, is it angular version?
One more thing i forgot to mention, the one's in mine is not showing the dropdown as i typed.
UPDATE #2
I updated the plunker using angular 1.5.0 which is the one i am using, and its working, so its not angular version.
So after trying out a few things, i finally got it working by doing this
I reserved the Tag.getTags response object in a variable and call it on load rather than calling it every time user typed (or using the load-on-focus and or load-on-empty parameters) and using the filter method based on this example
controller
(function() {
'use strict';
angular
.module('contests')
.controller('ContestsAddController', ContestsAddController);
ContestsAddController.$inject = [
'$scope',
'$state',
'$location',
'Tag',
'toaster',
'lodash'
];
function ContestsAddController(
$scope,
$state,
$location,
Tag,
toaster,
lodash
) {
var vm = this;
/** Properties */
vm.tagList = [];
vm.tags = [];
/** Methods */
vm.loadTags = loadTags;
function loadTags($query) {
return vm.tagList.filter(function(tag) {
return tag.text.toLowerCase().indexOf($query.toLowerCase()) !== -1;
});
}
activate();
function activate() {
return _getTagList();
}
function _getTagList() {
Tag
.getTags()
.then(function(response) {
vm.tagList = response.data;
return vm.tagList;
});
}
}
}());
view (dont know if this is related)
<tags-input ng-model="vm.tags" display-property="text" add-from-autocomplete-only="true" text="text">
<auto-complete source="vm.loadTags($query)" debounce-delay="500"></auto-complete>
</tags-input>
So I created with angular a small factory to get my local json file now I wanna pass that data to my controller but it can't find the factory name and says 'unresolved variable'.
Here is the snippet of my code what I guess is relevant for now.
(function () {
var app = angular.module('locatieTool', ['ngRoute']);
app.controller('teamController', function ($scope) {
function init () {
dataFactory.getTeams().success(function(data) {
$scope.teams = data
});
}
init();
console.log($scope.teams);
});
// factory
app.factory('dataFactory', function($http) {
var team = {};
//get local data
team.getTeams = function() {
return $http.get ('http://localhost:4040/');
};
return team;
});
})();
My goal is just to console log the $scope.teams, than I can do more with the data.
you should include "dataFactory" inside your controller
(function () {
var app = angular.module('locatieTool', ['ngRoute']);
app.controller('teamController', function ($scope, dataFactory) {
function init () {
dataFactory.getTeams().success(function(data) {
$scope.teams = data
});
}
init();
console.log($scope.teams);
});
// factory
app.factory('dataFactory', function($http) {
var team = {};
//get local data
team.getTeams = function() {
return $http.get ('http://localhost:4040/');
};
return team;
}); })();
I believe you need to pass your factory into the controller:
app.controller('teamController', function ($scope, dataFactory) {
function init () {
dataFactory.getTeams().success(function(data) {
$scope.teams = data
});
}
init();
console.log($scope.teams);
});
How would i change the following code form $http.get to a $resource
//The created resource (not using it for now)
hq.factory('LogsOfUser', function ($resource) {
return $resource('/HQ/Graph/GetLoggedinTimes?userName=:userName', {
userName: '#userName'
})
});
//The Controller
var ModalViewLogActionsCtrl = function ($scope, $http, $log, LogsOfUser, $modal) {
$scope.openLogs = function (userName) {
$http.get("/HQ/Graph/GetLoggedinTimes?userName=" + userName).success(function (data) {
var modalInstance = $modal.open({
templateUrl: 'LogView.html',
controller: 'ModalLogViewInstance',
resolve: {
items: function () {
//$scope.items = data;
$log.log(data);
$scope.items = data;
return $scope.items; //return data;
},
userName: function () {
return userName;
}
}
});
}).error(function () {
alert("eror :(");
});;
};
};
You've already done most of the work. All you need now is to call the service inside the controller :
LogsOfUser.query({
userName: userName
}, function success(data) {
//your code
}, function err() {
alert("Error")
});
Use query to get an array of data, and get to get a single document.
Here is a example how to call a resource from a controller:
app.controller('MainCtrl', function($scope, $resource) {
var userName = 'Bob';
var LoggedinTimes = $resource('/HQ/Graph/GetLoggedinTimes');
var data = LoggedinTimes.get({userName : userName}, function () {
console.log(data);
});
});
First, you would want to move data-related logic behind a Service, so your controller doesn't know about server-specifics. More importantly, your Service becomes reusable as all services in AngularJS are global singletons. your controller stays small, as it should be.
Next, your controller would call getLoggedIntimes() and work with the outcome as if the data is there. The result of a $resource.get() or similar functions return an empty object or array which fills itself when the REST call returns with data.
In your service you would do the actual $resource.get().
something along the lines of the following pseudo code:
//The Controller
var ModalViewLogActionsCtrl = function ($scope, MyService, $log, LogsOfUser, $modal) {
$scope.openLogs = function (userName) {
var items = MyService.getLoggedInTimes(userName);
var modalInstance = $modal.open({
templateUrl: 'LogView.html',
controller: 'ModalLogViewInstance',
resolve: {
items: function () {
$scope.items = items;
return $scope.items;
},
userName: function () {
return userName;
}
}
});
};
};
app.service('MyService', function ($resource) {
var loggedInResource = $resource('/HQ/Graph/GetLoggedinTimes/:userName');
return {
getLoggedInTimes: functio(username) {
return loggedInResource.get({
username: username
});
}
};
});
Following Dan Wahlin's article on dynamically loading controllers and views http://weblogs.asp.net/dwahlin/archive/2013/05/22/dynamically-loading-controllers-and-views-with-angularjs-and-requirejs.aspx, I coded an sample AngularJS application with one minor modification as follows.
While Dan for example loads the data service ahead of time (main.js), I would lile to load a factory only if a controller needs it like this:
main.js
require.config({
baseUrl: '/app'
});
require([
'app',
'services/routeResolver'
//'services/mathService'
],
function () {
angular.bootstrap(document, ['myFirstApp'])
});
mathService.js
'use strict';
define(['app'], function (app) {
var mathService = function () {
return {
add: function(n1, n2) {
if (isNaN(n1) || isNaN(n2)) {
return NaN;
}
return parseInt(n1) + parseInt(n2);
}
}
};
app.factory('mathService', mathService);
});
v2Controller.js
'use strict';
define(['app', 'services/mathService'], function (app) {
var ctrl = function ($scope, mathService) {
$scope.greeting = 'Hi there from viewtwoland!';
$scope.n1 = 0;
$scope.n2 = 0;
$scope.result = 0;
$scope.add = function ()
{
$scope.result = mathService.add($scope.n1, $scope.n2);
}
};
app.register.controller('v2Controller', ['$scope', 'mathService', ctrl]);
});
v2.html
<p>
{{greeting}}
</p>
<input type="text" data-ng-model="n1" id="n1" name="n1" data-ng-change="add()" />
<input type="text" data-ng-model="n2" id="n2" name="n2" data-ng-change="add()" />
<div>
The sum of {{n1}} and {{n2}} is: {{result}}
</div>
This is however not working as expected. Here is the result I am getting:
{{greeting}}
[ ] [ ]
The sum of {{n1}} and {{n2}} is: {{result}}
Any ideas. Is this doable at all.
I resolved the issue by changing the controller as follows:
define(['app', 'services/mathService'], function (app) {
var ctrl = function ($scope, mathService) {
$scope.greeting = 'Hi there from viewtwoland!';
$scope.n1 = 0;
$scope.n2 = 0;
$scope.result = 0;
$scope.add = function ()
{
return mathService.add($scope.n1, $scope.n2);
}
};
app.register.controller('v2Controller', ['$scope', 'mathService', ctrl]);
});
and the mathService as follows:
'use strict';
define(['app'], function (app) {
var mathService = function () {
return {
add: function(n1, n2) {
if (isNaN(n1) || isNaN(n2)) {
return NaN;
}
return parseInt(n1) + parseInt(n2);
}
}
};
app.register.factory('mathService', mathService);
});
If you have a better solution for this issue, I'd be interesting in knowing it.