Okay so right now I am messing around with the ionic framework and learning angularJS at the same time. I just came across $q and async calls, but I just can't seem to get it right. I want to be able to parse a JSON file which I already have set up using GetJsonSpecials then pass that to GetData which will then pass it to my controller SpecialsCtrl so I can attach it to $scope. I know I am not understanding the promises correctly because everything inside SpecialService undefined. I can get the data perfectly fine from the other two serivces, but when I try passing it to SpecialService it all just seems to crumble which in turn ends up as undefined in my controller. Maybe I am not going about this the right way? Are there any best practices of doing this kind of thing?
angular.module('starter.controllers', [])
.controller('SpecialsCtrl', function ($scope, SpecialService) {
$scope.specials = SpecialService.all();
console.log("Specials Controller: Got Data", $scope.specials);
})
//Create methods to access the specials inside the controller in which we inject this in
.factory('SpecialService', function (GetData) {
var specials = GetData.getSpecials();
console.log("DATAAAA: ", specials);
return {
// Return all specials
all: function () {
console.log("Inside return with specials: ", specials);
return specials;
},
getSpecialWithId : function (specialId) {
// Simple index lookup
return specials[i];
}
}
}
})
.factory('GetData', function(GetJsonSpecials) {
return {
getSpecials : function() {
GetJsonSpecials.retrieveData().then(function (data) {
console.log("Got the JSON data", data);
return data;
}, function (status) {
alert("Error getting specicals", status);
console.log("Error getting specicals", status);
});
}
}
})
//Asynchronously get the specials from the json file
.factory('GetJsonSpecials', function ($q, $http) {
return {
retrieveData : function() {
var deferred = $q.defer();
$http.get('js/specials.json').success(function (data, status) {
deferred.resolve(data);
}).error(function (status) {
deferred.reject(status);
console.log("Error in handling json!");
});
return deferred.promise;
}
}
})
The reason I have this overly complicated is because in the end I want to be able to share the data to another controller which will display that specific specials' properties in a new view.
.controller('DetailCtrl', function ($scope, $stateParams, JsonSpecials, $firebaseAuth) {
$scope.id = parseInt($stateParams.specialId);
$scope.special = JsonSpecials.getSpecialWithId($scope.id);
})
There are a few problems here. The main issue being that angularjs promises are asynchronous and you're trying to use them in a synchronous manner.
First off, you having an extra } after your SpecialService definition.
In your SpecialService:
.factory('SpecialService', function (GetData) {
var specials = GetData.getSpecials();
This will be nothing because your GetData.getSpecials() returns nothing.
If you were to fix GetData.getSepcials to return:
getSpecials : function() {
return GetJsonSpecials.retrieveData().then(function (data) {
console.log("Got the JSON data", data);
return data;
}, function (status) {
alert("Error getting specicals", status);
console.log("Error getting specicals", status);
});
}
then back in your SpecialService, you need to change how you get the data back.
var specials = GetData.getSpecials();
won't give you your data either. It will be a promise because it is asynchronous. So it needs to be
GetData.getSpecials().then(function(data) {
return data;
});
Also, as Matt as pointed out, in your retrieveData definition, you're creating an unnecessary promise. So
retrieveData : function() {
var deferred = $q.defer();
$http.get('js/specials.json').success(function (data, status) {
deferred.resolve(data);
}).error(function (status) {
deferred.reject(status);
console.log("Error in handling json!");
});
return deferred.promise;
}
is the same as:
retrieveData : function() {
return $http.get('js/specials.json').error(function (status) {
console.log("Error in handling json!");
return status;
});
}
It seems you are over complicating things a bit. You're passing data around factories for no clear reason. I think those three factories could be combined into just one. Maybe try something like..
index.html
<!DOCTYPE html>
<html ng-app="foobar">
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div ng-controller="SpecialsCtrl">
{{specials}}
</div>
<div ng-controller="AnotherController">
{{specials}}
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="script.js"></script>
</body>
</html>
script.js
angular.module('foobar', [])
.controller('SpecialsCtrl', function ($scope, JsonSpecials) {
JsonSpecials.retrieveData().then(function(data){
$scope.specials = data;
});
})
.controller('AnotherController', function ($scope, JsonSpecials) {
JsonSpecials.retrieveData().then(function(data){
$scope.specials = data;
});
})
//$http returns a promise anyway so you don't need $q
.factory('JsonSpecials', function ($http){
return {
retrieveData : function() {
return $http
.get('js/specials.json')
.error(function (status) {
console.log("Error in handling json!");
});
}
}
});
Related
I searched for this but I did not get any answer as I want, please give me a solution, I want to use ng-init inside ng-repeat, ng-init should give me different response at every loop here is my HTML
<html>
<body ng-app="crmApp">
<div ng-controller="customerDetailController">
<div ng-repeat="clientDetail in client">
<p>{{clientDetail.name}}</p>
<div ng-init="seoDetails = getCustDetail(clientDetail.name)">
<p>{{seoDetails.cust_Name}}</p>
</div>
</div>
</div>
</body>
</html>
and my js is
<script>
var crmMain = angular.module('crmApp', ['ngRoute','ngMaterial']);
crmMain.controller('customerDetailController',function customerDetailController($scope, $http, customerDetailFactory,$window) {
$scope.client = [];
$scope.init = function () {
$scope.getCustomerData();
};
$scope.getCustomerData = function () {
customerDetailFactory.getCustomerDetailData().then(function
(response) {
$scope.client = response.data;
});
};
$scope.getCustDetail = function (Name) {
var custDetail = [];
custDetail = customerDetailFactory.getCustomerDetailData(Name).then(function (response) {
alert(response.data.cust_Name);
return response.data;
});
return custDetail;
};
$scope.init();
});
crmMain.factory('customerDetailFactory', ['$http', function ($http) {
var factory = {};
var url = 'phpFile/customerDetail.php';
factory.getCustomerDetailData = function (Name) {
return $http({
method: 'POST',
url: url,
data: {
'functionName': 'clientDetailPage',
'customerName': Name
}
});
};
return factory;
}]);
</script>
In inside getCustDetail function I was given alert in there it 'll show name, but I don't know why it not showing in HTML.is anything wrong I did?
I have got one solution for this, I think I have to use Promises for this, but I don't know how to use it can anyone help me in this?
You cannot use ng-init for this purpose.
You've to do the data fetching inside the controller itself. That is like,
customerDetailFactory.getCustomerDetailData()
.then(function(response) {
$scope.client = response.data;
// for each clients, fetch 'seoDetails'
$scope.client.forEach(function(client) {
customerDetailFactory.getCustomerDetailData(client.name)
.then(function (response) {
// I hope response.data contains 'cust_Name'
client.seoDetails = response.data;
})
});
});
Now, in the view, you can directly use the seoDetails property
<div ng-repeat="clientDetail in client">
<p>{{clientDetail.name}}</p>
<p>{{clientDetail.seoDetails.cust_Name}}</p>
</div>
My goal is to get $http to work on my local filesystem by caching some static JSON objects in a $cacheFactory. I wish to avoid network requests entirely and use only cached content.
The issue is that $http is making server requests regardless of the existence of cached content. My code is as follows.
Cache Factory
myApp.factory('jsonCache', function($cacheFactory){
// create new cache object
// (tried $cacheFactory.get('$http') as well, but same result)
var cache = $cacheFactory('jsonCache');
// put static value in cache
cache.put('/json/file1.json', {"key":"value"});
return cache;
});
Factory using $http
myApp.factory('AjaxFactory', function($http, jsonCache){
console.log(jsonCache.info()); // {id: 'jsonCache', size: 1}
// this will make a request to "http://localhost/json/file1.json"
// even though there is an entry for that URL in the cache object
$http.get('/json/file1.json', {cache: jsonCache}).success(/* ... */);
return { /* ... */ };
});
At this point I'm thinking it may be the format of the data I'm using in cache.put(), but unsure.
Please see demo code below, commends should help you a bit
var app = angular.module('app', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
//
// For any unmatched url, redirect to /state1
$urlRouterProvider.otherwise("/state1");
//
// Now set up the states
$stateProvider.state('state1', {
url: "/state1",
template: "<h1>State1 </h1> <pre>{{cache | json}}</pre>",
controller: 'state1Ctrl'
})
.state('state2', {
url: "/state2",
template: "<h1>State2 </h1><pre>{{cache | json}}</pre>",
controller: 'state2Ctrl'
});
});
app.controller('state1Ctrl', function($scope, myCache) {
var cache = myCache.cache.get('jsonCache');
//check if cached data exist
if (cache) {
//use cached data
$scope.cache = myCache.cache.get('jsonCache');
//if not update cache
} else {
myCache.update().success(function(data) {
//set cache
myCache.cache.put('jsonCache', data.info);
console.log(myCache.cache.info());
//get cached data
$scope.cache = myCache.cache.get('jsonCache');
}).error(function() {
console.log("error");
});
}
});
app.controller('state2Ctrl', function($scope, myCache) {
var cache = myCache.cache.get('jsonCache');
if (cache) {
$scope.cache = myCache.cache.get('jsonCache');
} else {
myCache.update().success(function(data) {
myCache.cache.put('jsonCache', data.info);
console.log(myCache.cache.info());
$scope.cache = myCache.cache.get('jsonCache');
}).error(function() {
console.log("error");
});
}
});
app.factory('myCache', function($cacheFactory, $http) {
// create new cache object
var cache = $cacheFactory('jsonCache');
// put static value in cache
function update() {
alert("update")
return $http.get("https://ws.spotify.com/search/1/track.json?q=kaizers+orchestra");
}
return {
cache: cache,
update: update
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js"></script>
<script src="
https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.13/angular-ui-router.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
<body ng-app="app">
<div ui-view></div>
<!-- We'll also add some navigation: -->
<a ui-sref="state1">State 1</a>
<a ui-sref="state2">State 2</a>
</body>
I was actually able to get it working as desired on this plunk http://plnkr.co/edit/x1nfjwEoJOxzZN5PUyrX?p=preview
angular.module("myApp", [])
.factory('jsonCache', function($cacheFactory) {
// create new cache object
// (tried $cacheFactory.get('$http') as well, but same result)
var cache = $cacheFactory('jsonCache');
// put static value in cache
cache.put('file1.json', {
"key": "From Cache Factory"
});
return cache;
})
.factory('jsonFactory', function($http, jsonCache) {
var get = function(url) {
return $http.get(url, {
cache: jsonCache
});
};
return {
get: get
};
})
.controller("Ctrl", function($scope, jsonFactory, jsonCache) {
$scope.cacheInfo = jsonCache.info();
jsonFactory.get('file1.json').success(function(res) {
$scope.json = res;
});
});
I think the issue with my original code was the result of one of the many 3rd party module dependencies. (doh!)
My workaround for the code as it was, was the following:
myApp.factory('jsonFactory', function($http, $q, jsonCache){
var get = function(url){
var data = jsonCache.get(url);
// if data exists in cache, wrap in promise and return
// or do regular $http get
if(data){
return $q(function(resolve, reject){ resolve(data); });
} else {
return $http.get(url);
}
};
return {
get: get
};
});
i'm building application which uses CORS requests. Each request i use get host address from a constant
angular.module('siteApp').constant('baseUrl', {
'server':'htttp://localhost/',
})
And in each service i use to send request like this:
angular.module('siteApp').factory('DocsSvc', function ($http, baseUrl) {
var baseurl = baseUrl.server ;
$http.get(baseurl + 'document')
Is it possible to make 'htttp://localhost/' value - to came from config.json file into baseUrl constant or baseUrl factory?
I mean : how can i load something from ajax request an make it accessible to app modules
i have tried:
.run(['$rootScope', , function ($rootScope) {
$.ajax('config.json', {async: false})
.success(function (data) {
$rootScope.HOST = data.HOST;
});
And tried to access it from baseUrl:
angular.module('siteApp').factory('baseUrl',function($rootScope) {
return {
server: $rootScope.HOST
But no luck - the baseUrl.server comes undefined into functions
You can use run method of angular.
var app = angular.module('plunker', []);
app.run(function($http, $rootScope){
$http.get('config.json')
.success(function(data, status, headers, config) {
$rootScope.config = data;
$rootScope.$broadcast('config-loaded');
})
.error(function(data, status, headers, config) {
// log error
alert('error');
});
})
app.controller('MainCtrl', function($scope, $rootScope) {
$scope.$on('config-loaded', function(){
$scope.name = $rootScope.config.name;
});
});
see this plunker
If you want to do it even before the angular app starts, you can, instead of using the ng-app directive, use the bootstrap function.
From:
https://docs.angularjs.org/api/ng/function/angular.bootstrap
<!doctype html>
<html>
<body>
<div ng-controller="WelcomeController">
{{greeting}}
</div>
<script src="angular.js"></script>
<script>
var app = angular.module('demo', [])
.controller('WelcomeController', function($scope) {
$scope.greeting = 'Welcome!';
});
// Do your loading of JSON here
angular.bootstrap(document, ['demo']);
</script>
</body>
</html>
You need to tell angular about data change, so modify your code something like this:
.run(['$rootScope', function ($rootScope) {
$.ajax('config.json', {async: false})
.success(function (data) {
$rootScope.HOST = data.HOST;
$rootScope.$apply(); // New line
});
}])
That $apply() is needed since its a non-angular asynchronous call.
use the blow code snippet to load the json values
.run(function ($http, $rootScope) {
$http.get('launchSettings.json')
.success(function (data, status, headers, config) {
$rootScope.config = data;
$rootScope.$broadcast('config-loaded');
})
.error(function (data, status, headers, config) {
// log error
alert('error');
});
});
I would like to display data returned from service call into view:
Service Code :
.service('HomeExchangeList', function ($rootScope, $http, $log) {
this.getHomeExchange = function() {
var rates = $http({
method: 'GET',
url: 'http://localhost:8080/feeds/homerates_android.php'
}).success(function (data) {
$log.log(data);
return data;
});
return homeRates;
};
})
JSON Data returned by service
{
"record":[
{
"Name":"GBP\/USD",
"Ticker":"GBP\/USD",
"Price":"0.5828",
"Open":"0.5835",
"High":"0.5848",
"Low":"0.5828",
"PercentagePriceChange":"0.1371",
"Movement":"0.0800",
"DateStamp":"2014\/07\/09",
"TimeStamp":"22:15:00"
},
{
"Name":"EUR\/USD",
"Ticker":"EUR\/USD",
"Price":"0.7330",
"Open":"0.7344",
"High":"0.7351",
"Low":"0.7327",
"PercentagePriceChange":"0.2585",
"Movement":"0.1900",
"DateStamp":"2014\/07\/09",
"TimeStamp":"22:15:00"
},
{
"Name":"GHS\/USD",
"Ticker":"GHS\/USD",
"Price":"3.3350",
"Open":"3.2650",
"High":"3.3500",
"Low":"3.2650",
"PercentagePriceChange":"0.8915",
"Movement":"3.0000",
"DateStamp":"2014\/07\/09",
"TimeStamp":"22:15:00"
},
{
"Name":"KES\/USD",
"Ticker":"KES\/USD",
"Price":"87.7000",
"Open":"86.2970",
"High":"87.6500",
"Low":"86.1800",
"PercentagePriceChange":"0.0661",
"Movement":"5.8000",
"DateStamp":"2014\/07\/09",
"TimeStamp":"22:15:00"
},
{
"Name":"MUR\/USD",
"Ticker":"MUR\/USD",
"Price":"30.2925",
"Open":"29.1460",
"High":"29.4300",
"Low":"29.0500",
"PercentagePriceChange":"-0.0909",
"Movement":"-2.7500",
"DateStamp":"2014\/07\/09",
"TimeStamp":"22:15:00"
},
{
"Name":"MWK\/USD",
"Ticker":"MWK\/USD",
"Price":"393.5000",
"Open":"393.3900",
"High":"393.3900",
"Low":"385.0000",
"PercentagePriceChange":"-0.2548",
"Movement":"-100.0000",
"DateStamp":"2014\/07\/09",
"TimeStamp":"22:15:00"
},
{
"Name":"NGN\/USD",
"Ticker":"NGN\/USD",
"Price":"162.3000",
"Open":"160.0600",
"High":"162.4000",
"Low":"160.0600",
"PercentagePriceChange":"0.2459",
"Movement":"40.0000",
"DateStamp":"2014\/07\/09",
"TimeStamp":"22:15:00"
},
{
"Name":"ZAR\/USD",
"Ticker":"ZAR\/USD",
"Price":"10.6659",
"Open":"10.6751",
"High":"10.7162",
"Low":"10.6523",
"PercentagePriceChange":"0.9840",
"Movement":"10.6000",
"DateStamp":"2014\/07\/09",
"TimeStamp":"22:15:00"
},
{
"Name":"ZMK\/USD",
"Ticker":"ZMK\/USD",
"Price":"47.7014",
"Open":"47.3850",
"High":"47.7000",
"Low":"46.8900",
"PercentagePriceChange":"0.0067",
"Movement":"0.3165",
"DateStamp":"2013\/07\/27",
"TimeStamp":"01:55:00"
}
]
}
Controller code
function HomeCtrl($scope, Page, $location, HomeExchangeList) {
$scope.rates = HomeExchangeList.getHomeExchange();
$scope.$on('HomeExchangeList', function (event, data) {
$scope.exchangeRates = data;
});
}
View
<ul id="home-rates" ng-repeat="rate in exchangeRates">
<li><span class='rate-symbol'>{{rate.Name}}</span><span class='rate-amount'>{{rate.Price}}</span></li>
</ul>
I would like to display the data returned by in the service in the view but it doesn't seem to be working. Please help
First, $http invocations all return a promise, not the result of your request. Your service should just return the result of the $http call, and your controller needs to attach a .success handler to receive the data and set it on the scope of your controller.
.service('HomeExchangeList', function ($rootScope, $http, $log) {
this.getHomeExchange = function() {
var rates = $http({
method: 'GET',
url: 'http://localhost:8080/feeds/homerates_android.php'
}).success(function (data) {
$log.log(data);
// removed your return data; it doesn't do anything, and this success is only added to log the result. if you don't need the log other than for debugging, get rid of this success handler too.
});
return rates;
};
})
function HomeCtrl($scope, Page, $location, HomeExchangeList) {
HomeExchangeList.getHomeExchange().success(function(data) {
$scope.exchangeRates = data;
});
}
Second, the root of your JSON is not an array, so you can't enumerate through just exchangeRates alone. Perhaps you meant exchangeRates.record.
try to assign data.record to $scope.exchangeRates instead of data... as data doesnt hold the array of records... it holds record which then holds the array
First of all, your service function always returns undefined:
var rates = ...,
return homeRates;
It should be
return rates;
Second, once that is fixed, the service doesn't return data. It returns a promise, and you can't iterate on a promise. What you need in the controller is:
HomeExchangeList.getHomeExchange().then(function(data) {
$scope.rates = data.record;
}
The call to $scope.$on doesn't make any sense. $scope.$on is used to listen for events. Not to get data from a promise.
And finally, your view must iterate over these retes, and not over exchangeRates:
ng-repeat="rate in rates">
I have below ajax query which returns me json from controller
$(document).ready(function () {
$.getJSON(
"api/OutletPOC/GetHomeTab?bizId=1",
function (data) {
$("#homeTabDesc").append(data.HomeDesc);
$(".test").hide();
$("#hometabcontent").show();
});
});
the controller action is as below
[System.Web.Http.ActionName("GetHomeTab")]
public HomeTabModel GetHomeTab(int bizId)
{
var outlet = db.Info.Where(t => t.BizId == bizId).SingleOrDefault();
return new HomeTabModel
{
HomeDesc = outlet.BizHomeDesc,
HomeTabText = outlet.BizHomeTabText
};
}
Now my question is: curently i am sending hard coded value of bizId to web api. I want to send this value dynamically. How can i achieve this? I have that value in my route config file. The code is as below-
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{bizId}",
defaults: new { controller = "Home", action = "Index", bizId = 1 }
);
}
I am new to this. Please help! Thanks in advance!
no, actually after much research, i came up with this solution and this works fine for me....
In controller,
public ActionResult Index(int bizId)
{
ViewBag.BizId = bizId;
return View();
}
and in View,
$(document).ready(function () {
$.getJSON(
"api/OutletPOC/GetHomeTab?bizId=#ViewBag.BizId",
function (data) {
$("#homeTabDesc").append(data.HomeDesc);
$(".test").hide();
$("#hometabcontent").show();
});
});
You can pass a data object as part of the GetJson call.
$(document).ready(function () {
$.getJSON(
"api/OutletPOC/GetHomeTab",{bizId : 1},
function (data) {
$("#homeTabDesc").append(data.HomeDesc);
$(".test").hide();
$("#hometabcontent").show();
});
});
Taking this one step further you could wrap this in a function.
function makeCall(id)
{
$.getJSON("api/OutletPOC/GetHomeTab",{bizId : id},
function (data) {
$("#homeTabDesc").append(data.HomeDesc);
$(".test").hide();
$("#hometabcontent").show();
});
}
Also look into using promises.
$.getJSON().then().done();