Normalising controller in AngularJS - javascript

Am pretty new to AngularJS.
I have written a code and its working fine.
Would like to know, is there a way to further shrink the controller.
My index.html file is
<!DOCTYPE html>
<html lang="en-US">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="customersCtrl">
<input type="text" ng-model="sea" ng-change="newSearch()"/>
<ul>
<li ng-repeat="x in myData">
{{ x.name + ', ' + x.emailid}}
</li>
</ul>
</div>
<script src="js/app.js"></script>
<script src="js/controllers/maincontroller.js"></script>
</body>
</html>
And maincontroller.js is
app.controller('customersCtrl', function($scope, $http) {
$http(
{
url: "http://localhost:8080/cordovaprojects/123m/www/customer.php",
method: "GET",
params: {'name':'powercom'}
})
.then(function(response) {
$scope.myData = response.data.records;
});
$scope.newSearch = function() {
$scope.newSea = $scope.sea;
$http(
{
url: "http://localhost:8080/cordovaprojects/123m/www/customer.php",
method: "GET",
params: {'name':$scope.newSea}
})
.then(function(response) {
$scope.myData = response.data.records;
});
};
});
If you notice I have used the same $http function twice with a difference of param.
Thank you.

As #maurycy noted in his comment, the way to keep the size of your controllers small is to keep commonly used functionality inside of a service. Consider this service:
app.service('Customers',
[ '$http',
function($http) {
return {
byName: byName
};
function byName(name) {
return $http({
url: "http://localhost:8080/cordovaprojects/123m/www/customer.php",
method: "GET",
params: {'name': name}
});
}
}
]
);
You can then use this service in a controller like this:
app.controller('customersCtrl', [
'$scope', 'Customers',
function($scope, Customers) {
$scope.myData = null;
Customers.byName('powercom')
.then(function(response) {
$scope.myData = response;
});
}
]);
Which is quite a bit shorter than what you have now, plus it is separated making it able to be used in any other part of your application (as well as much easier to test). If the endpoint changes, you have only a single spot to change and, since it's used everywhere else already, you're done.
Update
To bind on an ng-click, I'll assume you have an input bound to a local model, as well as a button for which to act as the click target, something like this:
<input type="text" data-ng-model="customerName" />
<button data-ng-click="lookupCustomer()">
Lookup Customer
</button>
Then in your controller, you can define the lookupCustomer function this way:
app.controller('customersCtrl', [
'$scope', 'Customers',
function($scope, Customers) {
$scope.customerName = 'powercom';
$scope.lookupCustomer = lookupCustomer;
$scope.myData = null;
lookupCustomer();
function lookupCustomer() {
Customers.byName($scope.customerName)
.then(function(data) {
// Do something with data
});
}
}
]);
You can add checks inside of lookupCustomer to guard against edge cases (no need to lookup an empty customer name), but this should work for you.

It'll be better if you'll create the service for getting your data.
app.service('dataService', function($http) {
this.get = function get(param) {
return $http({
url: "http://localhost:8080/cordovaprojects/123m/www/customer.php",
method: "GET",
params: {'name': param}
});
}
});
app.controller('customersCtrl', function($scope, dataService) {
dataService.get('powercom').then(function(response) {
$scope.myData = response.data.records
});
$scope.newSearch = function() {
$scope.newSea = $scope.sea;
dataService.get($scope.newSea).then(function(response) {
$scope.myData = response.data.records
});
};
});
And also is not necessary to create a functions in your $scope. You can use "this" and get access for your data in controller by controller name or alias like this:
<div ng-controller="customersController as ctrl"><p ng-click="ctrl.newSearch">Hello</p></div>

Related

angular js the deugger doesn't get into the controller

when i debug my controller, it stuck at the initialization of the controller and doesn't get past it
here is the app
var app = angular.module('app', []);
and here is the controller and it's service
app.controller('UsersController', function ($scope, UsersService) {
$scope.User = [];
$scope.Image = [];
$scope.CV = [];
alert("Controller");
$scope.GetUserProfile = function (ID) {
alert("in");
UsersService.GetUserData(ID, function (Result) {
if (Result.success == true) {
$scope.User = Result.Content;
}
});
}
});
app.service('UsersService', function ($http) {
this.GetUserData = function (UserID,callback) {
var req = {
method: 'GET',
url: 'http://localhost:7598/tb/Profile/GetProfileByID',
headers: {
'Authorization': 'No Authentication'
},
params: {
'ID': UserID
}
}
$http(req).success(callback);
}
});
and in html i reference the Angular js file and the App file and the Controller file
here is the HTML
<script src="~/Scripts/angular.min.js"></script>
<script src="~/ScriptControllers/MainApp.js"></script>
<script src="~/ScriptControllers/UsersController.js"></script>
<div class="card hovercard" ng-controller="UsersController">
<div class="card-background" ng-init="GetUserProfile(5)">
It seems that you're missing an ng-app directive in the html, according to the html and js code you've posted. The browser just parses the js code but does not execute it.
<body ng-app="app"> ... </body>
Working example of your code: here

Need help on Angular Factory

Hi SO angular community !
I'm very confused, I think I have understand the factory purpose and concept, but seems not ...
Here is my problem (surely simple for you) :
I want to use my REST API (working perfectly) using Angular and .factory ...
rest.js
var app = angular.module('urlShortener', ['ngRoute', 'ngResource']);
app.factory('API', ['$resource',
function($resource){
return $resource('/link'});
}],{
get: {method:GET},
post: {method:POST},
put: {method:PUT},
delete: {method:DELETE},
}
);
app.controller('GetAll', function ($scope) {
$scope.links = API.get();
});
index.ejs
<div ng-controller="GetAll">
<ul>
<li ng-repeat="link in links">
<p>{{link.itemId}} --> {{link.url}}</p>
</li>
</ul>
</div>
Not working ... 2 hours I'm consulting the Angular API, and no solutions :/
Please help me I'm wasting time :'(
\\\\ SOLUTION ////
rest.js
app.factory('API', ['$resource', function($resource) { return $resource('/link'); }]);
app.controller('GetAll', ['$scope', 'API', function ($scope, API) {
API.query().$promise.then(function(links) {
$scope.links = links;
});
}]);
Thanks to #dfsq help :)
You can't just assign $resource instance to $scope.links, you need to do it when underlying promise resolves:
app.controller('GetAll', ['$scope', 'API', function ($scope, API) {
API.get().$promise.then(function(links) {
$scope.links = links;
});
}]);
You have to inject "API" in your controller.
app.controller('GetAll', function ($scope, API) {
$scope.links = API.get();
});
If your rest service returns an array of objects you need to use query function.
$scope.links = API.query(); // instead of API.get()
If you need to do anything else when the promise returns use something like this:
API.query().$promise.then(function(result){
$scope.links = result;
// any other operation related to the request here
});
if you want to do api requests, use $http
this is a piece of code I use in my app:
angular
.module('myApp')
.factory('apiFactory', apiFactory);
function apiFactory($http) {
return {
getDataFromApi: getDataFromApi,
};
function getDataFromApi(url) {
return $http({
method: 'GET', // or post or whatever
url: url,
headers: {
...
}
})
.then(success)
.catch(fail);
function success(response) {
return response.data;
}
function fail(response) {
// handle error
}
}
}
Is this what you are looking for?
API For Resources
services.factory('Api', ['$resource',
function($resource) {
return {
Recipe: $resource('/recipes/:id', {id: '#id'}),
Users: $resource('/users/:id', {id: '#id'}),
Group: $resource('/groups/:id', {id: '#id'})
};
}]);
function myCtrl($scope, Api){
$scope.recipe = Api.Recipe.get({id: 1});
$scope.users = Api.Users.query();
...
}

Saving data into JSON format through Post method

I am using AngularJS. I want to post the data in a file in JSON format to the localhost server i.e. http://localhost:8080/out.json.
How should the post method should be implement for this scenario ? OR Any other working example for the post method which are able to save the data in the json format is helpful.
Thanks.
Here is my code :
var app = angular.module('myApp', []);
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
]);
app.controller('FormCtrl', function ($scope, $http) {
$scope.data = {
firstname: "default"
};
$scope.submitForm=function($scope, $http) {
$http.post('someurl', JSON.stringify(data)).
success(function(data) {
console.log(data);
}).
error(function(data) {
console.log(data);
});
};
});
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<script src="controller.js"></script>
</head>
<body>
<div ng-controller="FormCtrl">
<form name="saveTemplateData" action="#">
First name: <input type="text" ng-model="data.firstname"> <br/><br/>
<button type="submit" ng-Click='submitForm()'>Submit</button>
</form>
</div>
</body>
</html>
Adding my comment as an answer:
Sounds like you're sending to a different domain than the one you're on.. in general you can't do that unless that domain accepts such requests.
You doesn't need to use the stringily function.
I think you forgot to put $scope. before data
try with this code :
$scope.submitForm=function($scope, $http) {
$http.post('someurl', $scope.data).
success(function(data) {
console.log(data);
}).
error(function(data) {
console.log(data);
});
};
EDIT
Oh I didn't see that but you don't need too specify $scope, $http again when you declare a function like submitForm. If you do it, you will have to variable named $scope which not will be in the same scope and you haven't access to data.
$scope.submitForm = function() {
$http.post('someurl', $scope.data).
success(function(data) {
console.log("success" + data);
}).
error(function(data) {
console.log("error" + data);
});
};

In AngularJS, how to initialize a provider with a dynamic value

Very new to AngularJS and looking at the code in this tutorial, http://www.thinkster.io/angularjs/eIaGNOAlOk/angularjs-providers.
var app = angular.module("app",[]);
app.provider("game", function () {
var type;
return {
setType: function (value) {
type = value;
},
$get: function () {
return: {
title: type + "Craft"
};
}
};
});
app.config(function (gameProvider) {
gameProvider.setType("War");
});
app.controller("AppCtrl", function ($scope, game) {
$scope.title = game.title;
});
So in the app.config we use setType("war") but what if this value is dynamic? When the page loads the value will be provided by the server and set in a HTML data attribute, something like:
<div ng-app="app" ng-controller="AppCtrl" data-type="space">
{{ title }}
</div>
Is this possible with providers?
Yes it is can be done using another provider method and then calling it inside the config. To make it simple you can also go for the factory method and inject the factory in the config and set the dynamic value
Basic Factory:
app.module('getValue', [])
.factory('fetchValue', function($http) {
return {
getType: function(callback) {
return $http({
method: 'GET',
url: "whatever you have"
}).
success(function(data) {
callback(data);
});
}
};
});
And in you app.config you can do like
app.config(function (gameProvider,fetchValue) {
fetchValue.getType(function(data){
gameProvider.setType(data);
});
});

Get Ajax data into Angular grid

Using Angular Grid, I get the ajax get data in console.log. But an empty grid.
The console log reads:
[13:56:11.411] now!!
[13:56:11.412] []
[13:56:11.412] now!!
[13:56:11.556] <there is data returned from console.log(getData); >
This is the js file.
// main.js
var app = angular.module('myApp', ['ngGrid']);
var getData = [];
function fetchData() {
var mydata = [];
$.ajax({
url:'/url/to/hell',
type:'GET',
success: function(data) {
for(i = 0, j = data.length; i < j; i++) {
mydata[i] = data[i];
}
getData = mydata;
console.log(getData);
}
});
}
fetchData();
app.controller('MyCtrl', function($scope) {
console.log('now!!')
console.log(getData)
console.log('now!!')
$scope.myData = getData
$scope.gridOptions = {
data: 'myData',
showGroupPanel: true
};
});
New Js file:
// main.js
var app = angular.module('myApp', ['ngGrid']);
app.controller('MyCtrl', function($scope, $http) {
function fetchData() {
$http({
url:'/url/to/hell',
type:'GET'})
.success(function(data) {
$scope.myData = data;
$scope.gridOptions = {
data: 'myData',
showGroupPanel: true
};
});
}
fetchData();
});
HTML file.
<html ng-app="myApp">
<head lang="en">
<meta charset="utf-8">
<title>Blank Title 3</title>
<link rel="stylesheet" type="text/css" href="http://angular-ui.github.com/ng-grid/css/ng-grid.css" />
<link rel="stylesheet" type="text/css" href="../static/css/style.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<script type="text/javascript" src="http://angular-ui.github.com/ng-grid/lib/ng-grid.debug.js"></script>
<script type="text/javascript" src="../static/js/main.js"></script>
</head>
<body ng-controller="MyCtrl">
<div class="gridStyle" ng-grid="gridOptions"></div>
</body>
</html>
This would be much easier (and more Angular) if you defined a service for your request. Something along these lines:
angular.module('hellServices', ['ngResource'])
.factory('Hell', function ($resource) {
return $resource('URL/TO/HELL', {}, {
query: { method: 'GET' }
});
});
Make sure to include it in your app:
var app = angular.module('myApp', ['ngGrid', 'hellServices']);
Then you can get a promise for it in your controller:
app.controller('MyCtrl', function($scope, $http, Hell) {
$scope.myData = Hell.query();
And then set the grid options to look at the promise for its data (as you already did):
$scope.gridOptions = {
data: 'myData',
showGroupPanel: true
};
If you do this, you don't have to worry about $scope.$apply because it will be handled for you. This is much cleaner and easier to follow. If you still need a callback to modify the data once it's returned from the server, pass a function to the query() function of your service:
...
$scope.myData = Hell.query(function(hell) {
// code that modifies 'hell'
});
Check out the official docs on Angular Services. The basics are also covered in Step #11 of the official Angular JS tutorial.
Your controller is probably accessing the getData array before the .success is finished. You're accessing the variable right away, outside of a promise function, which is initialized to an empty array.
Why don't you try putting the fetchData function into the controller (for now) and storing the getData directly into $scope.myData in the .success? Maybe even initialize the grid right there too? Not sure if you can do that but if you could it would look like this:
app.controller('MyCtrl', function($scope, $http) {
$scope.myData = '';
$scope.gridOptions = { showGroupPanel: true, data: 'myData' };
function fetchData() {
setTimeout(function(){
$http({
url:'/url/to/hell',
type:'GET'})
.success(function(data) {
$scope.myData = data;
if (!$scope.$$phase) {
$scope.$apply();
}
});
}, 3000);
}
fetchData();
});
(source for some of the $scope apply stuff: https://github.com/angular-ui/ng-grid/issues/39)
Also not sure why you're mixing in jQuery .ajax with angular code ($http will do that), and why none of your javascript has a semicolon.

Categories