AngularJS $service method invocation - javascript

I am a core java developer, now begining to learn AngularJS.
I am going through the tutorial pages and got the below doubt.
On of the example is
index.html
<div ng-app="invoice3" ng-controller="InvoiceController as invoice">
<b>Invoice:</b>
<div>
Quantity: <input type="number" min="0" ng-model="invoice.qty" required >
</div>
<div>
Costs: <input type="number" min="0" ng-model="invoice.cost" required >
<select ng-model="invoice.inCurr">
<option ng-repeat="c in invoice.currencies">{{c}}</option>
</select>
</div>
<div>
<b>Total:</b>
<span ng-repeat="c in invoice.currencies">
{{invoice.total(c) | currency:c}}
</span>
<button class="btn" ng-click="invoice.pay()">Pay</button>
</div>
</div>
invoice3.js
angular.module('invoice3', ['finance3'])
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
this.qty = 1;
this.cost = 2;
this.inCurr = 'EUR';
this.currencies = currencyConverter.currencies;
this.total = function total(outCurr) {
return currencyConverter.convert(this.qty * this.cost, this.inCurr, outCurr);
};
this.pay = function pay() {
window.alert("Thanks!");
};
}]);
finance3.js
angular.module('finance3', [])
.factory('currencyConverter', ['$http', function($http) {
var YAHOO_FINANCE_URL_PATTERN =
'//query.yahooapis.com/v1/public/yql?q=select * from '+
'yahoo.finance.xchange where pair in ("PAIRS")&format=json&'+
'env=store://datatables.org/alltableswithkeys&callback=JSON_CALLBACK';
var currencies = ['USD', 'EUR', 'CNY'];
var usdToForeignRates = {};
var convert = function (amount, inCurr, outCurr) {
return amount * usdToForeignRates[outCurr] / usdToForeignRates[inCurr];
};
var refresh = function() {
var url = YAHOO_FINANCE_URL_PATTERN.
replace('PAIRS', 'USD' + currencies.join('","USD'));
return $http.jsonp(url).success(function(data) {
var newUsdToForeignRates = {};
angular.forEach(data.query.results.rate, function(rate) {
var currency = rate.id.substring(3,6);
newUsdToForeignRates[currency] = window.parseFloat(rate.Rate);
});
usdToForeignRates = newUsdToForeignRates;
});
};
refresh();
return {
currencies: currencies,
convert: convert,
refresh: refresh
};
}]);
In finance3.js, I am not clear when refresh() method will be called.
There is a call refresh() inside the function($http) of 'currencyConverter' service . But when this statement will be invoked ?
All I see is we invoke convert() from InvoiceController. But no calls to refresh method.

in your code 'finance3' is not a name of you ng-app in your html code for this reason i dont understand your code. for mora information about implementation of factory and his use I recommend you read this guide carefully Angular Style Guide is a very good guide with examples of code.
and i recommend implement the refresh in your controller.
greetings D

The thinking here is that we need to get some external currency data when the service is created AND we also want the possibility of being able to refresh this data at some later point in the application.
Then it makes sense to make a function refresh which we'll call once when the service is first invoked, as you noticed by calling refresh(). We then expose the refresh function as a service method, so any user of the service can request that the service update it's data.

AngularJS service/factory works same way as Java Singleton. So when your controller is initialized - code inside
angular.module('finance3', [])
.factory('currencyConverter', ['$http', function($http) {
Will be executed. It defines currencies array and 2 functions. refresh() is called once. (You're probably supposed to launch it later when you need to update.)
Here is the Java analog of this service:
public class Finance3 {
public static Finance3 INSTANCE = new Finance3();
public String[] currencies;
public Map<String, String> usdToForeignRates;
private Finance3() {
refresh();
}
private void refresh() {
new Thread(new Runnable(public void run() {
usdToForeignRates = Http.get(...)
})).start();
}
}

Related

Browser crashed when angularjs supply data on HTML datalist

I have a html datalist that supplies list of account name which around 14k+, it works fine but any browser that I used will not respond first then successfully supplied the data in datalist using ng-repeat. In worst case the browser crashed.
C# backend
public JsonResult getCollateralAccount() {
List<collateralAccount> accountlist = new List<collateralAccount>();
sqlHelper = new QueryHelper();
SqlParameter[] parameterList = { };
var table = sqlHelper.ExecuteQuery("collateralGetListOfAccount", System.Data.CommandType.StoredProcedure, parameterList).Tables[0];
accountlist = table.AsEnumerable().Select(row => new collateralAccount
{
Id = row.Field<int>("Id"),
name = row.Field<string>("name")
}).ToList();
return new JsonResult { Data = accountlist, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
Service
getCollateralAccount: function (data) {
var $getCollateralAccount = $http.get('/Collatera/getCollateralAccount').
success(function (data) {
return data;
});
return $getCollateralAccount;
}
Controller
$scope.listofCAccount = [];
CollateralService.getCollateralAccount().then(function(msg){
if(msg.data.length>0){
$scope.listofCAccount = msg.data;
}
});
View
<input id="username" type="text" class="form-control width100" list="UsersName" ng-model="user.name" required/>
<datalist id="UsersName">
<option ng-repeat="acc in accListContainer track by $index" value="{{acc.name}}" data-val="{{acc.name}}"></option>
</datalist>
Can anyone help me how to stop my browser from crashing or not responding?
success/error has been deprecated, also you are using then at your controller, so just change your service as below(return Promise of $http.get directly).
getCollateralAccount: function (data) {
return $http.get('/Collatera/getCollateralAccount');
}
14K result in an ng-repeat is for sure not what any user would like to see.
You could try limitTo filter if this applies to you. You can use it like this:
ng-repeat="acc in accListContainer | limitTo:10 track by $index"
For more interesting approaches see: How to improve performance of ngRepeat over a huge dataset (angular.js)?

Handle multiple item in single controller? AngularJS

I am relatively new to Angular JS. Currently I met a problem, lets say I have 1000 items in a list. In order to display the details about each item I will pass the items_id to generate html example(123.html). In this case, do I need 1000 controller to handle this kind of situation?
Controller
app.controller('item0001',function($scope,$http,$sce){
$scope.data = [];
$scope.details=[];
$http.get("https://api.com/test/product/0001").then(function(response){
var getData = response.data;
$scope.data.push(response.data);
$scope.bindHtml = $sce.trustAsHtml(getData.details);
for(var i = 0; i<getData.specification.length; i++){
$scope.details.push(getData.details[i]);
}
});
});
app.controller('item0002',function($scope,$http,$sce){
$scope.data = [];
$scope.details=[];
$http.get("https://api.com/test/product/0002").then(function(response){
var getData = response.data;
$scope.data.push(response.data);
$scope.bindHtml = $sce.trustAsHtml(getData.details);
for(var i = 0; i<getData.specification.length; i++){
$scope.details.push(getData.details[i]);
}
});
});
View
<p>
View More
</p>
Use single controller and HTML.
Bind the HTML with some ViewModel (a property on $scope)
From your controller place the call to fetch item details (I am assuming you have fetch these details on click of some button) using a service.
In success callback of your service update the view model. and angular using 2-way binding, will update the view with last item fetched.
Controller:
app.controller('ProductCtrl', function($scope, ProductService) {
var getProduct = function(productId) {
ProductService.getProduct(productId).then(function(response) {
$scope.productDetails = response.data;
})
};
});
Service:
app.factory('ProductService', function($http) {
return {
getProduct(productID) {
return $http({
method: 'GET',
url: "https://api.com/test/product/" + productID
});
};
}
});
HTML View:
<body ng-controller="ProductCtrl">
<div ng-init="getProduct(0001)">
<p>Name {{productDetails.name}}</p>
<p>ID {{productDetails.id}}</p>
<p>Description {{productDetails.description}}</p>
</div>
<button ng-click="getProduct(productDetails.id + 1)">Get Next Product</button>
</body>
I hope this gives you a basic idea of how to implement your requirement. Please elaborate your question so that I can provide a more specific solution.
Define a single view (html) and controller to handle this.. example below.
productDetails.html (view)
<div>
<span>{{productName}}</span>
</div>
productDetails.js (controller)
app.controller('productDetailsCtrl',function($scope,$http,$sce){
$scope.productName = "";
$http.get("https://api.com/test/product/0001").then(function(response){
var getData = response.data;
$scope.productName = getData.productName;
});
});

Ng-model with Cookie

I'm trying to take the first example from the angular.js homepage and adding in cookie support.
This is what I have so far: https://jsfiddle.net/y7dxa6n8/8/
It is:
<div ng-app="myApp">
<div ng-controller="MyController as mc">
<label>Name:</label>
<input type="text" ng-model="mc.user" placeholder="Enter a name here">
<hr>
<h1>Hello {{mc.user}}!</h1>
</div>
</div>
var myApp = angular.module('myApp', ['ngCookies']);
myApp.controller('MyController', [function($cookies) {
this.getCookieValue = function () {
$cookies.put('user', this.user);
return $cookies.get('user');
}
this.user = this.getCookieValue();
}]);
But it's not working, ive been trying to learn angular.
Thanks
I'd suggest you create a service as such in the app module:
app.service('shareDataService', ['$cookieStore', function ($cookieStore) {
var _setAppData = function (key, data) { //userId, userName) {
$cookieStore.put(key, data);
};
var _getAppData = function (key) {
var appData = $cookieStore.get(key);
return appData;
};
return {
setAppData: _setAppData,
getAppData: _getAppData
};
}]);
Inject the shareDataService in the controller to set and get cookie value
as:
//set
var userData = { 'userId': $scope.userId, 'userName': $scope.userName };
shareDataService.setAppData('userData', userData);
//get
var sharedUserData = shareDataService.getAppData('userData');
$scope.userId = sharedUserData.userId;
$scope.userName = sharedUserData.userName;
Working Fiddle: https://jsfiddle.net/y7dxa6n8/10/
I have used the cookie service between two controllers. Fill out the text box to see how it gets utilized.
ok, examined your code once again, and here is your answer
https://jsfiddle.net/wz3kgak3/
problem - wrong syntax: notice definition of controller, not using [] as second parameter
If you are using [] in controller, you must use it this way:
myApp.controller('MyController', ['$cookies', function($cookies) {
....
}]);
this "long" format is javascript uglyfier safe, when param $cookies will become a or b or so, and will be inaccessible as $cookies, so you are telling that controller: "first parameter in my function is cookies
problem: you are using angular 1.3.x, there is no method PUT or GET in $cookies, that methods are avalaible only in angular 1.4+, so you need to use it old way: $cookies.user = 'something'; and getter: var something = $cookies.user;
problem - you are not storing that cookie value, model is updated, but cookie is not automatically binded, so use $watch for watching changes in user and store it:
$watch('user', function(newValue) {
$cookies.user = newValues;
});
or do it via some event (click, submit or i dont know where)
EDIT: full working example with $scope
https://jsfiddle.net/mwcxv820/

Use http cookie value in an Angular template

I have angular working in one of my ASP.NET MVC applications. I am using two html templates with Angular Routing. One is a list of current Favorites that comes from the database and is serialized into json from my Web API and used by angular to list those items from the database.
The second html template is a form that will be used to add new favorites. When the overall page that includes my angular code loads, it has a cookie named currentSearch which is holding the value of whatever the last search parameters executed by the user.
I would like to inject this value into my angular html template (newFavoriteView.html) for the value of a hidden input named and id'd searchString.
I have tried using jQuery, but had problems, plus I would much rather do this inside of angular and somehow pass the value along to my template or do the work inside the view(template). However, I know the latter would be bad form. Below is the code I think is important for one to see in order to understand what I am doing.
Index.cshtml (My ASP.NET VIEW)
#{
ViewBag.Title = "Render Search";
ViewBag.InitModule = "renderIndex";
}
<div class="medium-12 column">
<div data-ng-view=""></div>
</div>
#section ngScripts {
<script src="~/ng-modules/render-index.js"></script>
}
Setting the cookie in the MVC Controller
private void LastSearch()
{
string lastSearch = null;
if (Request.Url != null)
{
var currentSearch = Request.Url.LocalPath + "?" +
Request.QueryString;
if (Request.Cookies["currentSearch"] != null)
{
lastSearch = Request.Cookies["currentSearch"].Value;
ViewBag.LastSearch = lastSearch;
}
if (lastSearch != currentSearch)
{
var current = new HttpCookie("currentSearch", currentSearch){
Expires = DateTime.Now.AddDays(1) };
Response.Cookies.Set(current);
var previous = new HttpCookie("lastSearch", lastSearch) {
Expires = DateTime.Now.AddDays(1) };
Response.Cookies.Set(previous);
}
}
}
render-index.js
angular
.module("renderIndex", ["ngRoute"])
.config(config)
.controller("favoritesController", favoritesController)
.controller("newFavoriteController", newFavoriteController);
function config($routeProvider) {
$routeProvider
.when("/", {
templateUrl: "/ng-templates/favoritesView.html",
controller: "favoritesController",
controllerAs: "vm"
})
.when("/newsearch", {
templateUrl: "/ng-templates/newFavoriteView.html",
controller: "newFavoriteController",
controllerAs: "vm"
})
.otherwise({ redirectTo: "/" });
};
function favoritesController($http) {
var vm = this;
vm.searches = [];
vm.isBusy = true;
$http.get("/api/favorites")
.success(function (result) {
vm.searches = result;
})
.error(function () {
alert('error/failed');
})
.then(function () {
vm.isBusy = false;
});
};
function newFavoriteController($http, $window) {
var vm = this;
vm.newFavorite = {};
vm.save = function () {
$http.post("/api/favorites", vm.newFavorite)
.success(function (result) {
var newFavorite = result.data;
//TODO: merge with existing topics
alert("Thanks for your post");
})
.error(function () {
alert("Your broken, go fix yourself!");
})
.then(function () {
$window.location = "#/";
});
};
};
favoritesView.html
<div class="container">
<h3>New Favorite</h3>
<form name="newFavoriteForm" ng-submit="vm.save()">
<fieldset>
<div class="row">
<div class="medium-12 column">
<input name="searchString" id="searchString" type="hidden"
ng-model="vm.newFavorite.searchString"/>
<label for="title">Name</label><br />
<input name="title" type="text"
ng-model="vm.newFavorite.name"/>
<label for="title">Description</label><br />
<textarea name="body" rows="5" cols="30"
ng-model="vm.newTopic.description"></textarea>
</div>
<div class="medium-12 column">
<input type="submit" class="tiny button radius" value="Save"/> |
Cancel
</div>
</div>
</fieldset>
</form>
</div>
My current attepts have been using jQuery at the end of the page after Angular has loaded and grab the cookie and stuff it in the hidden value. But I was not able to get that to work. I also thought about setting the value as a javascript variable (in my c# page) and then using that variable in angular some how. AM I going about this the right way?
Or should it be handled in the angular controller?...
I'm new to angular and the Angular Scope and a bit of ignorance are getting in the way. If any other info is needed I can make it available, thanks if you can help or guide me in the right direction.
You can do it by reading the cookie value using JavaScript, set it as a property of the $scope object and access it on the template.
//Inside your controllers
function favoritesController($http, $scope) {
//Get the cookie value using Js
var cookie = document.cookie; //the value is returned as a semi-colon separated key-value string, so split the string and get the important value
//Say the cookie string returned is 'currentSearch=AngularJS'
//Split the string and extract the cookie value
cookie = cookie.split("="); //I am assuming there's only one cookie set
//make the cookie available on $scope, can be accessed in templates now
$scope.searchString = cookie[1];
}
EXTRA NOTE
In AngularJS, the scope is the glue between your application's controllers and your view. The controller and the view share this scope object. The scope is like the model of your application. Since both the controller and the view share the same scope object, it can be used to communicate between the two. The scope can contain the data and the functions that will run in the view. Take note that every controller has its own scope. The $scope object must be injected into the controller if you want to access it.
For example:
//inject $http and $scope so you can use them in the controller
function favoritesController($http, $scope) {
Whatever is stored on the scope can be accessed on the view and the value of a scope property can also be set from the view. The scope object is important for Angular's two-way data binding.
Sorry if I'm misunderstanding or over-simplifying, but...assuming JavaScript can read this cookie-value, you could just have your controller read it and assign it to a $scope variable?
If JavaScript can't read the value, then you could have your ASP write the value to a JavaScript inline script tag. This feels yuckier though.
Update to show controller-as example.
Assuming your HTML looked something vaguely like this:
<div ng-controller="MyController as controller">
<!-- other HTML goes here -->
<input name="searchString" id="searchString" type="hidden" ng-model="controller.data.currentSearch"/>
Then your controller may look something like this:
app.controller('MyController', function ($scope, $cookies) {
$scope.data = {
currentSearch: $cookies.currentSearch
};
// Note that the model is nested in a 'data' object to ensure that
// any ngIf (or similar) directives in your HTML pass by reference
// instead of value (so 2-way binding works).
});

Saving an item through factory casts an error with AngularJS and Firebase

I'm using Firebase and AngularJS bundled up together and as I'm in the learningprocess of both, I guess. I'm having some trouble saving an item through a factory with Angular.
This is my script
var app = angular.module('LinkApp', ['firebase']);
app.constant('FirebaseLinks', 'https://[hidden].firebaseio.com/links')
app.controller('LinkCtrl', ['$scope', 'LinksFactory',
function($scope, LinksFactory) {
// get links
$scope.links = LinksFactory.getItems();
// update link
$scope.updateLink = function(link) {
LinksFactory.updateItem(link);
};
}
]);
app.factory('LinksFactory', ['$firebase', 'FirebaseLinks',
function($firebase, FirebaseLinks) {
var ref = new Firebase(FirebaseLinks);
var items = $firebase(ref);
return {
getItems: function() {
return items.$asArray();
},
updateItem: function(item) {
items.$save(item);
}
};
}
]);
This is my html
<div ng-repeat="link in links | orderBy: link.number">
<input type="number" ng-model="link.number" ng-blur="updateLink(link)">
{{ link.name }}: {{ link.url }}
</div>
I'm using my blur function (updateLink) to pass my item into my factory, but from there I get this error: "TypeError: undefined is not a function".
If I pass my item to my function and save my collection from there width $scope.links.$save(link), it is successfull.
How can this be?
Thanks in regards. Say if you need further details.
After a lot of work I figured it out.
I had to return my factory functions and I had to call my variable 'items' with an $asArray() at the end and remove the $asArray() from my getItems function.
But now it works :)

Categories

Resources