This question already has answers here:
Passing data between controllers in Angular JS?
(18 answers)
Closed 8 years ago.
I want to try to pass data that was taken from an api:
Javascript:
function RecentCars($scope, $http){
$scope.cars = [];
$http({method:'GET'; url:'/recent'}).success(function(data,status){
$scope.cars = data;
});
$scope.clickThatCar =function(){
// want to pass that cars data to the CarPage Controller
}
}
function CarPage($scope, data){
// get the data for the car that was clicked
}
The HTML:
<div ng-repeat="motor in cars">
<div class="car_row" ng-click="clickThatCar()">
<img class="car_img" src="/images/{{motor._id}}_0.jpg">
<div class="car_info">
<span class="brand_name">{{motor.brand}}</span>
<span class="price">4,200 KD</span>
</div>
</div>
</div>
Im listing some cars using ng-repeat and that bit works fine, however when i click clickThatCar element, I want to just pass the data for the car that was clicked only. Im really new to angular :(
You can pass the car info in the ng-click call. Your code would look like this:
<div ng-repeat="motor in cars">
<div class="car_row" ng-click="clickThatCar(motor)">
<img class="car_img" src="/images/{{motor._id}}_0.jpg">
<div class="car_info">
<span class="brand_name">{{motor.brand}}</span>
<span class="price">4,200 KD</span>
</div>
</div>
</div>
Related
I am making a simple sports goods shopping app in AngularJs.
I am in a situation where I have three nested ng-repeats.
First loop: Get the brand name. I have written angularjs service that calls the rest endpoint to fetch the lists of brands (Adidas, Yonex, Stiga, etc). I am calling this service as soon as the page(controller) gets loaded.
Second loop: For each brand, I want to display the category of products they are offering. Inside this loop, I want to execute a function/service that will take the brand name as input and get all the categories for the brand. For this, I also have an angularjs service that calls the rest endpoint to fetch the list of categories for a given brand name.
Third loop: For each brand and category, I want to display the products in that category. Inside this loop, I want to execute a function that will take the brand name and category as input and get all the products in that category. I an angularjs service call which will call the rest endpoint to fetch the products given the brand name and category.
Sample data set:
Adidas
-----T-Shirts
----------V-Neck
----------RoundNeck
-----Shoes
----------Sports Shoes
----------LifeStyle Shoes
Yonex
-----Badminton Racquet
----------Cabonex
----------Nanospeed
-----Shuttlecocks
----------Plastic
----------Feather
Stiga
-----Paddle
----------Procarbon
----------Semi-carbon
-----Ping Pong Balls
----------Light Weight
----------Heavy Weight
Please note that because of some constraints I cannot have a domain object on the REST side to mimic the data structure shown above.
I want to display the above data in a tree-like fashion (something on the same lines as shown above possibly with expand/collapse options).
Below are the code snippets.
CONTROLLER:
(function () {
'use strict';
angular.module('SportsShoppingApp.controllers').controller('sportsController', ['sportsService', '$scope', function (sportsService, $scope) {
$scope.brands = [];
$scope.categories = [];
$scope.products = {};
$scope.getBrands = function () {
sportsService.getBrands()
.then(loadBrands, serviceError);
};
var loadBrands = function(response) {
$scope.brands= response.data;
};
$scope.getCategories = function(brand) {
sportsService.getCategories(brand)
.then(loadCategories, serviceError);
};
var loadCategories = function (response) {
$scope.categories = response.data;
};
$scope.getProducts = function(brand, category) {
sportsService.getProducts(brand, category)
.then(loadProducts, serviceError);
};
var loadProducts = function (response) {
$scope.products = response.data;
};
var serviceError = function (errorMsg) {
console.log(errorMsg);
};
$scope.getBrands();
}]);
}());
HTML:
<div class="well">
<div class="row">
<div id="sportsHeader" class="col-md-3">
<div ng-repeat="brand in brands.data">
<div class="row">
<div class="col-md-9">{{brand}}</div>
</div>
<div ng-repeat="category in categories.data" ng-init="getCategories(brand)">
<div class="row">
<div class="col-md-9">{{category}}</div>
</div>
<div ng-repeat="product in products.data" ng-init="getProducts(brand, category)">
<div class="row">
<div class="col-md-9">{{product}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
When I use the above HTML, only the brand names are displayed on the UI. The categories and their corresponding products are not displayed. I know that there is some overlapping that is happening. I am not sure if I am doing it the right way. I might be completely wrong with my approach. I am new to AngularJS. I want to know how to loop in nested ng-repeat so that each ng-repeat could call an angularjs service and also I want to display the data in the tree fashion as shown above. Can someone help me here?
I think that the ng-inits have to be placed on separate tags to the ng-repeats:
<div class="well">
<div class="row">
<div id="sportsHeader" class="col-md-3">
<div ng-repeat="brand in brands.data">
<div class="row">
<div class="col-md-9">{{brand}}</div>
</div>
<div ng-init="getCategories(brand)">
<div ng-repeat="category in categories.data">
<div class="row">
<div class="col-md-9">{{category}}</div>
</div>
<div ng-init="getProducts(brand, category)">
<div ng-repeat="product in products.data">
<div class="row">
<div class="col-md-9">{{product}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
You might have to juggle your bootstrap classes around also, moving ng-init is only to fix the angular part.
Move the ng-init directives outside of the ng-repeat to which they provide data.
<div class="well">
<div class="row">
<div id="sportsHeader" class="col-md-3">
<!-- MOVE init of categories here -->
<div ng-repeat="brand in brands.data" ng-init="getCategories(brand)">
<div class="row">
<div class="col-md-9">{{brand}}</div>
</div>
<!-- MOVE init of products here -->
<div ng-repeat="category in categories.data" ng-init="getProducts(brand, category)">
<div class="row">
<div class="col-md-9">{{category}}</div>
</div>
<div ng-repeat="product in products.data">
<div class="row">
<div class="col-md-9">{{product}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
The ng-init directive has a priority of 450; the ng-repeat, priority 1000. This means that when they are on the same element ng-init executes after the ng-repeat directive. The ng-repeat for categories.data won't execute its ng-init until it has a category. Thus its ng-init can't be used to populate the categories array.
Quick question. Is my approach correct ?
The approach works but it violates the Zen of Angular and the principles of an MV* Model View Whatever framework.
The model is the Single Source of Truth
Because the view is just a projection of the model, the controller is completely separated from the view and unaware of it. This makes testing a snap because it is easy to test your controller in isolation without the view and the related DOM/browser dependency.
--AngularJS Developer Guide -- Data-Binding
Having the ng-repeat and ng-init directives build the model creates a dependency that makes testing and debugging difficult. (As witnessed by this question.)
My advice is to learn how to build the model by chaining promises and using $q.all.
I have a page which shows different data with ng-ifs, I need to show how many of them are true on the same page. Just the number. The HTML is complex, but I have made a simpler version to understand how things work. Here is what the HTML looks like, and the data is being manipulated on the page as well, so the ng-if value can change after it has been rendered and hence the count on the page should be changing with it.
<div ng-if="abc">
some data 1
</div>
<div ng-if="!abc">
some data 2
</div>
<div ng-if="xyz">
some data 3
</div>
<div ng-if="abc">
some data 4
</div>
<div ng-if="!xyz">
some data 5
</div>
I made a plnkr as well.
http://plnkr.co/edit/5wdiSLhbHpOPJGjRn47L?p=preview
Thank you.
A pure JavaScript solution could be to add a class (or an attribute) to the HTML elements which have ng-if conditions, and then use document.getElementsByClassName('class-name').length to get the number of elements which have the ng-if condition true.
Example:
<div class="sample-class" ng-if="abc">
some data 1
</div>
<div class="sample-class" ng-if="!abc">
some data 2
</div>
<div class="sample-class" ng-if="xyz">
some data 3
</div>
<div class="sample-class" ng-if="abc">
some data 4
</div>
<div class="sample-class" ng-if="!xyz">
some data 5
</div>
<div>Total count is: {{getCount(); totalCount}}</div>
<script type="text/javascript">
angular.module('app', [])
.controller('ctrl', function($scope, $timeout) {
$scope.totalCount = 0;
$scope.getCount = function(){
$timeout(function(){
$scope.totalCount = document.getElementsByClassName('sample-class').length;
});
};
});
</script>
I have found an issue in AngularJS which relates to wrong update of view. It occurs from time to time. The problem is when model gets a new value, view is not updated by new model value, but old value is appended by new model value.
While troubleshooting I checked that model contains a correct value.
Here is a view.
<div class="container">
<div ng-repeat="p in point" id="{{'point-' + p.Id}}" class="{{p.BackgroundClass}}">
<div class="point-number">{{p.Id}}</div>
<div class="{{p.ImageClass}}"></div>
<div class="point-amount">{{p.Amount}}</div>
<div class="point-quantity">{{p.Quantity}}</div>
</div>
</div>
Controller code which contains SignalR events processing:
wetApiHubProxy.on('updatePointState', function (pointId, backgroundClassProp, imageClassProp) {
pointsService.getPointById(pointId).then(function (point) {
point.BackgroundClass = backgroundClassProp;
console.log('imageClassProp ' + point.ImageClass);
point.ImageClass = imageClassProp;
});
});
p.ImageClass is changing quite often. Changes/updates of view work in a correct way until sometimes occurs concatenation of old and new value.
Old p.ImageClass value is "point-state-configure".
New p.ImageClass value is "pump-state-off".
As a wrong result I have, where ImageClass contains concatenated values:
<div ng-repeat="p in points" id="point-4" class="point point-off" role="button" tabindex="0" style="">
<div class="point-number ng-binding">4</div>
<div class="point-state-configure pump-state-off" style=""></div>
<div class="point-amount ng-binding">926.93</div>
<div class="point-quantity ng-binding">417.35 L</div>
</div>
I have tried to call $scope.$apply() and $evalAsync, but that was hopeless. The strangest thing that issue occurs spontaneously. The only constant condition it's when $rootscope contains bigger amount of child scopes. Can anyone tell what place to dig and how to get rid of this problem?
class attribute is not intended to be used this way. You should use the ng-class directive instead.
I've created an example for you: https://jsfiddle.net/coldcue/o7q6gfs4/
JavaScript
angular.module('testApp', [])
.controller("TestController", function($scope) {
// Initialize the value
$scope.state = "state-blue";
// Change class on click
$scope.click = function() {
$scope.state = ($scope.state === "state-blue") ? "state-red" : "state-blue";
}
});
HTML
<div ng-controller="TestController">
<div ng-class="state">
Some label
</div>
<input type="button" ng-click="click()" value="Click me">
</div>
But there are many more ways to use ng-class, read more here: https://docs.angularjs.org/api/ng/directive/ngClass
Hi I have following data i get using factory in angular.
$scope.data=[{actId:12, acctName: "Tom James"}, {acctId:20, acctName: "Lisa Anderson"}]
In my html code I am using ng-repeat to display just the name.
<div ng-repeat=" record in data">
<div>{{record.acctName}}</div>
<div><button ng-click="getDetails(record)">Get Details</div>
</div>
In my controller I have
$scope.getDetails=function(record)
{
alert(record.actId)
}
In my controller I am trying to see if acctId is passed I get undefined error. Please let me know how I can pass the current record with all of its fields.
Thanks
There is spelling mistake use record.actId insted of record.acctId
If you want to get actId then you have to pass actId in getDetails function.
<div ng-repeat=" record in data">
<div>{{record.acctName}}</div>
<div><button ng-click="getDetails(record.actId)">Get Details</div>
</div>
in Controller
$scope.getDetails=function(actId)
{
alert(actId);
}
If you want to pass both accName and actId then here is the code for do this:-
<div ng-repeat=" record in data">
<div>{{record.acctName}}</div>
<div><button ng-click="getDetails(record.acctName,record.actId)">Get Details</div>
</div>
In Controller
$scope.getDetails=function(acName,actId)
{
alert(acName);// this is for name
alert(actId); //For Id
}
I am a newbie in angularjs and needs to pass a model bind value in a function which is declared in controller but when I accesss that value from controller it says undefined. Below is the code
HTML:
<div>
<p g-bind-template>{{model.myname}}</p>
<div>
<div data-ng-controller="formCtrl" data-ng-init="init(model.myname)"></div>
</div>
</div>
In the above HTML when i do {{model.myname}} I can see the value but how to pass it in init method.
In Controller I have wrote a function
$scope.init = function (myname) {
alert(myname) // displays undefined
};
Your paragraph tag should be within the ng-controller in html. Make it like this:
<div>
<div>
<div data-ng-controller="formCtrl" data-ng-init="init(model.myname)">
<p g-bind-template>{{model.myname}}</p>
</div>
</div>
</div>