$http.get() loops with ngrepeat - angularjs

I have 2 entities as below
person {
personID,
personName,
Array of Cars (Person Car)
}
Cars {
carID,
carName
}
And then the relational entity for Person-Car as below
PersonCar {
personID,
CarID,
relatedProperty1,
relatedProperty2
}
Now, to represent this on data on a HTML page, I'm doing the below
<div class="row" ng-repeat="person in persons">
<div class="col-xs-6">
{{person.personID}} - {{person.personName}}
</div>
<div class="col-xs-6">
<div class="row">
<div class="col-xs-12" ng-repeat="car in cars">
{{person.carID}} - {{getCarName(person.carID)}} -
{{person.relatedProperty1}} - {{person.relatedProperty2}}
</div>
<!-- Each Car-->
</div>
<!-- Array of Cars-->
</div>
<!-- Array of Cars Section -->
</div>
<!-- Person Row-->
Further, the data is being retrieved as below
modelInfo.controller('modelInfoController', function ($scope, $http, $filter) {
$http.get('http://localhost/person/123').
success(function(data) {
$scope.persons = data
}
$scope.getCarName = function(carID) {
$http.get('http://localhost/car/54545').
success(function(data) {
$scope.persons = data.carName
}
}
};
For some unknown reason, the script loops infinitely over the getCarName function. Please help me understand the issue. Also, please let me know if this is a good REST architecture.

You were missing a couple closing parenthesizes
modelInfo.controller('modelInfoController', function ($scope, $http, $filter) {
$http.get('http://localhost/person/123').success(
function(data) {
$scope.persons = data
}
); // <-- here, closing success function call
$scope.getCarName = function(carID) {
$http.get('http://localhost/car/54545').success(
function(data) {
$scope.persons = data.carName;
}
); // <-- here too
};
}); // <-- and here, closing the controller call
As for REST, it depends on how your backend server endpoints are defined
Although on the client side, you could define services for your resources, i.e. a wrapper for $http with REST methods (get, put, delete, update)

Related

how to send id from one controller to another in angular

I have a basic controller that displays my Software Group name:
var SoftwareGroupApp = angular.module('SoftwareGroupApp', []);
SoftwareGroupApp.controller('SoftwareGroupController', function($scope, $http) {
$http.get("select_SoftwareGroup.php")
.then(function (response) {$scope.result = response.data.records;});
});
In my view I'm displaying this Software Group in a list
<ul class="sub-menu">
<div ng-app="SoftwareGroupApp" ng-controller="SoftwareGroupController">
<li ng-repeat="x in result"><a class="haschild" title="" href="">{{ x.GroupName }}</a>
<ul>
<div ng-controller="SoftwareController">
<li ng-repeat="x in names"><a title="" href="">{{ x.name }}</a></li>
</div>
</ul>
</li>
</div>
</ul>
and i have another controller that display my Software name :
var SoftwareApp = angular.module('SoftwareApp', []);
SoftwareApp.controller('SoftwareController', function($scope, $http) {
$http.get("selectSoftware.php")
.then(function (response) {$scope.names = response.data.records;});
});
when someone click on the Software Group name, i have another sub menu that list my software name .
<ul>
<div ng-controller="SoftwareController">
<li ng-repeat="x in names"><a title="" href="">{{ x.name }}</a></li>
</div>
</ul>
What I'm trying to do is when someone click on the Software Group name, my Software group id save in a variable and send to my SoftwareController . and i display names of software that == id
I would suggest you to use $rootScope.broadcast for this kind of operation. To be very short you can use broadcast like this.
I one controller where you want to send data write like this:
$rootScope.$broadcast("yourFuction", data);
In the receiver controller get this data like this:
$rootScope.$on("yourFuction", function(data){
//do something
});
check this for more information: https://docs.angularjs.org/api/ng/type/$rootScope.Scope
Thanks.
Your best solution would be to use uirouter, rather than ng-controller, and pass the ID as a state parameter.
Another option would be to use components rather than ng-controller, which you can pass parameters to.
There are so many ways. I will mention you one way:
You can create a service to store Id which you want to send into another controller like below:
angular.module('app').factory('commonService', function () {
var myValue;
return {
set: function (o) {
this.myValue = o;
},
get: function () {
return this.myValue;
}
};
});
Now, inject this service into both controller like below:
angular.module('app').controller('firstController', function ($scope, commonService) {
$scope.setValue = function (value) {
commonService.set(value);
};
});
And,
angular.module('app').controller('SecondController', function ($scope, commonService) {
$scope.getValue = function () {
$scope.value = commonService.get();
};
});

AngularJs and two Controllers

I am writing an application that is running AngularJs & Bootstrap on the frontend - and using angularjs' $http to make calls to an API...I have two controllers within one app -- the first controller displays the person's name and the second controller displays a list of performances that this person has seen...
<html lang="en" ng-app="myapp">
...
<div class="panel-body" ng-controller="Ctrl">
<div class="row">
<div class="col-sm-3" style="height: 50px;">
<div class="well well-sm">
First Name:
{{ user.fname || "empty" }}
</div>
</div>
<div class="col-sm-3" style="height: 50px;">
<div class="well well-sm">
Last Name:
{{ user.lname || "empty" }}
</div>
</div>
</div>
</div>
<div class="list-group" ng-controller="Ctrl2">
<div ng-repeat="obj in performances" >
<div class="list-group-item">
<h4 class="list-group-item-heading">
<span class="badge">
{{$index+1}}</span> {{ obj["Perf_name"] || "empty" }}</h4>
<p class="list-group-item-text">
Date: {{ obj["Perf_dt"] || "empty" }}<br />
Theater: {{ obj["Theater"] || "empty" }}<br />
</p>
</div>
</div>
</div>
...
</html>
In the JS file I have the following code
Declare my variables and module
var app = angular.module("myapp", ["xeditable"]);
var q = getUrlParameter("q"); // get the query param
var baseurl = "https://some.domain/service/getCRM";
var baseurl2 = "https://some.domain/service/getPerformances";
Create a service to be used by both controllers
app.service('crmService', function () {
this.id = 0;
this.getID = function () { return this.id };
this.setID = function (newid) { this.id = newid; };
});
Define Controller #1
app.controller('Ctrl', function ($scope, $http, crmService) {
$http({
method: 'GET',
url: baseurl,
respondType: 'json',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
params: {
phone_no: q
}
}).then(function successCallback(response) {
$scope.user = {
fname: response.data[0]["FirstName"],
lname: response.data[0]["LastName"]
}
crmService.setID(response.data[0]["CRM_ID"]);
console.log("*** OUTPUT LINE 1: " + crmService.getID());
}, function errorCallback(response) {
console.log("**ERROR");
console.log(response);
});
});
Define Controller #2
app.controller('Ctrl2', function ($scope, $http, crmService) {
console.log("*** OUTPUT LINE 2: " + crmService.getID());
var promise = $http.get(baseurl2 + "?crm_id=" + crmService.getID());
promise.then(
function (response) {
$scope.performances = response.data;
});
});
Console output
*** OUTPUT LINE 2: 0
*** OUTPUT LINE 1: 123456
Questions:
Why is the second controller outputting before the first, I assume it is because AngularJs by default executes its code asynchronously, and if that's the case, why did the "promise" not work?
What I need to happen is, I make my GET call in the first controller block and assign the customer ID using my service...I then go on to the second controller block and using the customer ID, from my service (which was set within the first controller block) - get the customer's performances
So I have to first controller working fine, but the second controller keeps thinking that the customer ID is 0 - when it should be 123456
What am I missing?
FYI: when I hard code an ID for the second controller to use, I get actual performance records back - so I know everything will work once I figure out how to share values between my controllers
Why is the second controller outputting before the first
Because the second controller logs the ID as soon as it's instanciated, whereas the first one logs it once it has received, asynchronously, a response to an HTTP request. The promise did work, since the output is logged in the console.
What I need to happen is, I make my GET call in the first controller block and assign the customer ID using my service...I then go on to the second controller block and using the customer ID, from my service
You're doing your job more complex than it should be: using a single controller would be much easier here, since the model of the second one depends on what the first one does.
You could broadcast an event from the first controller to signal that the ID has been set, and listen to the event in the second one to get the data at tis time.
app.controller('Ctrl', function ($scope, $http, $rootScope, crmService) {
$http({
...
}).then(function successCallback(response) {
...
crmService.setID(response.data[0]["CRM_ID"]);
console.log("*** OUTPUT LINE 1: " + crmService.getID());
$rootScope.$broadcast('crmIdChanged');
};
});
app.controller('Ctrl2', function ($scope, $http, crmService) {
function getPerformances() {
var id = crmService.getID();
if (id != 0) {
var promise = $http.get(baseurl2 + "?crm_id=" + crmService.getID());
promise.then(
function (response) {
$scope.performances = response.data;
});
}
}
getPerformances();
$scope.$on('crmIdChanged', getPerformances);
});
You could even broadcast the even from the service itself.

Why the value couldn't show in the view after communicate between two controllers?

I met this problem again.Could anybody help me with this?
the first view:
<a type="button" ui-sref="index.usermng.userInfo" ng-click="checkUserInfo(item.id)" class="btn btn-primary">CheckUser</a>
the first controller:
$scope.checkUserInfo = function(userId) {
$rootScope.$broadcast('toUserInfo', userId);
}
the second view:
<div class="tab-pane active tab-chrome" id="tab-chrome">
<div class="row feature">
<div class="col-md-12">
<ul class="list-group">
<li class="list-group-item">UserId:{{data.user.userId}}</li>
<li class="list-group-item">Name:{{data.user.name}}</li>
<li class="list-group-item">Sex:{{data.user.sex}}</li>
<li class="list-group-item">Birthday:{{data.user.birthday | date:'yyyy-MM-dd'}}</li>
<li class="list-group-item">Mobile:{{data.user.mobile}}</li>
</ul>
</div>
</div>
</div>
the second controller:
userApp.controller('userInfoCtrl', ['$scope', '$http', '$rootScope', 'serverUrl', function($scope, $http, $rootScope, serverUrl) {
$rootScope.$on('toUserInfo', function(event, userId) {
console.log(userId); //i can get userId here
$http.get(serverUrl + "/user/info?userId=" + userId).success(function(data) {
console.log(data); // i can get data here
//if (data.code == 0) {
// $scope.detailUserID = userId;
// $scope.detailUserName = data.data.user.name;
// $scope.detailSex = data.data.user.sex;
// $scope.detailBirthday = data.data.user.birthday;
// $scope.detailMobile = data.data.user.mobile;
// $scope.detailCash = data.data.accumulate.usableCash;
$scope.data = data.data
}
//can't show in the view
})
})
}])
the config:
.state('index.usermng.userInfo',{
url: '/userInfo',
templateUrl: 'tpls/userInfo.html',
controller: 'userInfoCtrl'
})
In the second controller,I can get userId from the first controller,and I can get the data,but the view shows nothing,where is wrong?
This is a well known pitfall of Angular. It has to do with the fact that in the template the value is not updated because the scope variables are passed as values and that happens only once, when your view is rendered. That is normal Javascript behaviour.
The way around it is to place all the values on an object. I suggest you do this in your controller:
$scope.data = data.data
and in your templates you change it like this:
<li class="list-group-item">Name:{{data.user.name}}</li>
and so on
A good rule of thumb here is: if there is no dot in the variable in the template, then there is something wrong.
BTW, a more favourable approach is to use controllerAs, which forces you to use a dot in variable names in the template

Prevent ngRepeat flicker with promise in AngularJS

I have a collection of objects, say Products, which I can interact with using $resource. On an index page, I'd like to either display the collection, or, in the case the collection is empty, display a helpful message. i.e.
In Controller
$scope.products = Products.query();
In Template
<div ng-repeat="product in products">
...
</div>
<div class="alert" ng-hide="products.length">
<p>Oops, no products!</p>
</div>
This works fine, provided the user isn't staring at the spot where the ng-repeat will occur. If they are, or if there is a delay in the response from the server, they may notice a slight flicker, before the promise is resolved.
Given that, "invoking a $resource object method immediately returns an empty reference" (see here), such a flicker will always in this example. Instead, I find myself writing:
<div class="alert" ng-hide="!products.$resolved || products.length">
<p>Oops, no products!</p>
</div>
Which takes care of the flicker. However, I'm not too keen on letting my view know exactly how the products are obtained. Especially if I change this later on. Is there anything cleaner I could do? I'm aware that a fallback for ng-repeat is in the works (see here), however, just wondering if there's a cleaner solution in the meantime.
You could use the success method to set the object:
Products.query(function(data) {
$scope.products = data;
});
Or use the promise:
Products.query().$promise.then(function(data) {
$scope.products = data;
});
This way, the object doesn't become empty until you get a response.
You can get $promise out of $resource and change displayed information before/after promise is resolved.
Say you have following Products and service to get them.
/* products */
[
{ "id":1, "name":"name1" },
{ "id":2, "name":"name2" },
...
]
/***/
app.factory('Products', function ($resource) {
return $resource('products.json');
});
Then in your controller assign data only after promise is resolved.
app.controller('MainCtrl', function ($scope, Products) {
$scope.initialize = function () {
$scope.products = null;
Products.query().$promise.then(function (data) {
$scope.products = data;
});
};
$scope.initialize();
});
In your HTML template you can take care of the cases like a) not yet resolved b) resolved c) resolved but no data
<body ng-controller="MainCtrl">
<div ng-show="!products">
Getting data... please wait
</div>
<div ng-show="products && products.length === 0">
Oh noes!1 :( No products
</div>
<div ng-show="products">
<span ng-repeat="product in products">
{{ product | json }} <br>
</span>
</div>
<div>
<button type="button" ng-click="initialize()">Refresh</button>
</div>
</body>
Related plunker here http://plnkr.co/edit/Ggzyz9

AngularJS - Passing data between pages

I am an AngularJS starter. I am trying to send data from :
Page A : Van Listing page
to
Page B: Van Update page.
When user click the update link for a van, I am invoking a controller and retrieving the van details in the controller. But, I cannot assign the van details to the Page B ( Van Update Page) using the same controller... Error "Cannot set property 'vanNumber' of undefined"
*** Page A: Van List ****
<form name="listVanForm" >
<table>
<tr> <td ng-controller="VanUpdateCtrl">update</td> </tr>
</table>
</form>
*** Page B: Van Update ****
<div class="container">
<h2>Edit Van </h2>
<form name="updateVanForm" novalidate="novalidate" class="form-horizontal" ng-submit="updateCard(formData)">
<div class="control-group">
<label class="control-label" >Van Number:</label>
<div class="controls">
<input type="text" id="vanNumber" ng-model="formData.vanNumber" placeholder=""/>
</div>
</div>
</form>
</div>
*** VanUpdateCtrl **
app.controller('VanUpdateCtrl', ['$scope', 'VanUpdateFactory', '$location',
function ($scope, VanUpdateFactory, $location) {
//callback for ng-init 'populateDD':
$scope.prePopulateForm = function (cardNoParam m) {
alert('cardNo = '+cardNoParam);
$scope.formData.cardNumber=cardNoParam;}
}
So, $scope.formData.cardNumber OR $scope.formData in the destination page is not recognised.
You need to create a service to be able to share data between controllers.
app.factory('myService', function() {
var savedData = {}
function set(data) {
savedData = data;
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
});
In your controller A:
myService.set(yourSharedData);
In your controller B:
$scope.desiredLocation = myService.get();
Remember to inject myService in the controllers by passing it as a parameter.
What you should do is create a service to share data between controllers.
Nice tutorial https://www.youtube.com/watch?v=HXpHV5gWgyk
If you only need to share data between views/scopes/controllers, the easiest way is to store it in $rootScope. However, if you need a shared function, it is better to define a service to do that.
app.factory('persistObject', function () {
var persistObject = [];
function set(objectName, data) {
persistObject[objectName] = data;
}
function get(objectName) {
return persistObject[objectName];
}
return {
set: set,
get: get
}
});
Fill it with data like this
persistObject.set('objectName', data);
Get the object data like this
persistObject.get('objectName');

Resources