i have a table which is having the data retrieved from an api call from my memberController which is displayed inside ng-repeat and its working fine.
I need each Business Name of the member list to link to a separate page(edit_form.html) and display the id value, so that i can pass this along with the api call to get only this particular member detail. So i have added ng-init in my edit form page which calls the function test_funct when the page loads and retrieve each persons id there. unfortunately i am unable to retrieve the id value inside the function.
HTML Template
<div class="page" data-ng-controller="memberController">
<table>
<thead >
<tr>
<th>Business Name</th>
<th>Contact Name</th>
<th>Trade Balance</th>
<th>Cash Balance</th>
<th>Telephone</th>
<th>Account Number </th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="member in details | filter:search">
<td>{{member.businessname}}</td>
<td>{{member.person}}</td>
<td>{{member.balance_trade}}</td>
<td>{{member.balance_cash}}</td>
<td>{{member.telephone}}</td>
<td>{{member.accountnumber}}</td>
</tr>
</tbody>
</table>
</div>
I have the following controller
function memberController($scope, $http, $cookieStore) {
var token = $cookieStore.get('token');
var conId = $cookieStore.get('Cont_Id');
var exId = $cookieStore.get('ex_Id');
var member_list = "http://www.vb.com/functions/member_list.html?exchangeid=" + exId +
"&contactid=" + conId + "&token=" + token;
$http.get(member_list)
.success(function(response) {
$scope.details = response;
});
$scope.test_funct = function(id) {
$scope.myid = id;
alert($scope.myid); // getting undefined in alert, i expect the id(eg:1123)
}
}
edit_form.html
<div class="page" data-ng-controller="memberController">
<div class="panel-body" ng-init="test_funct()"></div>
</div>
Please assist me on this. Thanks in advance.
There are 2 things going on here.
First, you should separate controllers for the different views, so you end up with something like this:
<div class="page" data-ng-controller="memberController">
<table>
<!-- your whole big table here -->
</table>
</div>
And your editing form as follows:
<div class="page" data-ng-controller="editController">
<div class="panel-body"></div>
</div>
Notice that you now have two distinct controllers - your "editController" and your "memberController".
The second question then becomes, how do you transfer the selected ID from the list view ("memberController") to the edit view ("editController").
There are 2 ways of doing that.
First, you could use a service shared between the controller:
.factory('SelectedId',function() {
return {};
});
And then in your "member" view, you would set it upon clicking:
{{member.businessname}}
Notice the ng-click, which then needs a function in the memberController and the injected service:
.controller('memberController',function($scope,SelectedId) {
$scope.setId = function(id) {
SelectedId.id = id;
};
});
While the editController retrieves it:
.controller('editController',function($scope,SelectedId) {
$scope.id = SelectedId.id;
});
The above option works well, especially for complex things like shopping carts. If all you are doing is passing an ID, I would just stick it in the URL:
{{member.businessname}}
So that the ID is part of the URL. You then can retrieve it in the "editController":
.controller('editController',function($scope,$routeParams) {
$scope.id = $routeParams.member;
});
assuming you are using ng-route, and your route would look like:
$routeProvider.when('/pages/edit_form/:member',{templateUrl:'/route/to/template.html',controller:'editController'});
In html do that
<td>{{member.businessname}}</td>
...
In app.js or where you define route do that
.when('/edit/:memberid',
{
templateUrl:'partials/edit.html',
controller:'editController'
})
In controller you have to take this id by doing that
app.controller("editController",function($routeParams,$scope){
$scope.memberid= $routeParams.memberid;
//Now use this member id to fetch all data
});
Related
Very new to Angularjs. So I have some JSON files that I am reading into my webpage that contain and array of objects that are cars. What I am trying to do is have my "button" when pressed alert me to the data specific to that button.
The ng-repeat is running 8 times so that is the length of the array, but in angularJs i'm not sure how to basically store the array index for each time the ng-repeat passes in my button function.
This is my a snippet of my .html:
<div class="carTable table-responsive text-center" ng-controller="ButtonController" >
<table class="table specTable">
<thead>
<tr>
<th>Make</th>
<th>Model</th>
<th>Year</th>
<th>Color</th>
<th>Milage</th>
<th>Doors</th>
<th class="reserve">Horsepower</th>
<th>Price</th>
<th class="reserve"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="cars in car | orderBy:'year'">
<td>{{cars.year}}</td>
<td>{{cars.model}}</td>
<td>{{cars.make}}</td>
<td>{{cars.color}}</td>
<td>{{cars.mileage | number}}</td>
<td>{{cars.doors}}</td>
<td>{{cars.horsepower}}</td>
<td>{{cars.price | number}}</td>
<td><div class="panel panel-default">Reserve</div></td>
</tr>
</tbody>
</table>
</div>
The portion in question is at the bottom where I have a Reserve "button"
I'm leaving out my JSON files, works properly there. I'm just not sure how to keep track of the array index as the ng-repeat does its thing.
Here is the angular:
(function(){
var app = angular.module("myReserveApp", []);
app.controller("ButtonController", ["$scope", "$window", function($scope, $window){
$scope.buttonPress = function(){
$window.alert(JSON.stringify($scope.car[0]));
}
}]);
var MainController = function($scope, $http, $window){
var onGatherBoatData = function(response){
$scope.boat = response.data;
};
var onError = function(reason){
$scope.error = "Could not fetch Boat Data";
};
var onGatherCarData = function(response){
$scope.car = response.data;
};
var onError = function(reason){
$scope.error = "Could not fetch Car Data";
};
var onGatherTruckData = function(response){
$scope.truck = response.data;
};
var onError = function(reason){
$scope.error = "Could not fetch Truck Data";
};
$scope.message = "Hello, Angular Here!";
};
app.controller("MainController", ["$scope", "$http", "$window", MainController]);
}());
Currently in the top portion of the code I just have it alerting object[0] but I want it to be specific to which button is pressed. Any help is appreciated, thank you.
$index refers to the index in ng-repeat. So if you want to pass your function the index in array on the button click, change buttonPress() to buttonPress($index)
you'll have to change your controller to something like the following:
$scope.buttonPress = function(index){
$window.alert(JSON.stringify($scope.car[index]));
}
To do the following, you can just pass the current data in the ngRepeat. Moreover,if you want the current index, the ngRepeat directive provide specials properties, as the $index, which is an iterator.
$scope.buttonPress = function(car, index){
//Retrieve current data of the ngRepeat loop
console.log(car);
//Current index of your data into the array
console.log(index);
}
Then you can call your function like this :
Reserve
First, thank you both for the quick responses. Both of these answers work. I found another way to do it as well before reading your posts.
<div class="panel panel-default">
Reserve:{{car.indexOf(cars)}}
</div>
Using (car.indexOf(cars)) gives me the same result
$scope.buttonPress = function(index){
$window.alert(JSON.stringify(index));
}
Now when I click on the "button" it sends me back the array index, so now I should be able to play with that data. Thank you again both, for your help.
I wanted to have nested controllers like this...
Controller 1 - This is the parent. It is populated from a JSON array that comes from a REST and uses ngRepeat.
Controller 2 - This is the child. It should get data from a REST call as well, but it needs to know which parent object it is under.
Here's a visual...
Parent 1
---Child 1
---Child 2
---Child 3
Parent 2
---Child 4
---Child 5
---Child 6
The children will be populated by calling a REST service and passing info about the parent.
Make sense?
Here is some HTML that I have structured...
<div ng-app="App">
<div ng-controller="spRisks">
<table width="100%" cellpadding="10" cellspacing="2" class="employee-table">
<tr ng-repeat="risk in Risks">
<td>
<table width="100%" cellpadding="10" cellspacing="2" class="employee-table">
<tr id="{{risk.Id}}RiskDesc">
<td>{{risk.Risk_x0020_Description}}</td>
</tr>
<tr id="{{risk.Id}}RiskControls">
<td>
<div ng-controller="spControls">
<table width="100%" cellpadding="10" cellspacing="2" class="employee-table">
<tr ng-repeat="control in Controls">
<td id="{{control.Id}}Control">{{control.Title}}</td>
<td>
<input type="radio" name="{{control.Id}}Answer" value="Yes">Yes
<input type="radio" name="{{control.Id}}Answer" value="No">No
</td>
<td>
<textarea id="{{control.Id}}Comment"></textarea>
</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
</div>
And here is some code I have working that populates the parent controller...
<script>
function getDataWithCaml(listName, caml) {
var endpoint = "https://myteamsite.sharepoint.com//_api/web/lists/GetByTitle('" + listName + "')/GetItems(query=#v1)?#v1={\"ViewXml\":\"'" + caml + "'\"}";
return jQuery.ajax({
url: endpoint,
method: "POST",
headers: {
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"Accept": "application/json;odata=verbose",
"Content-Type": "application/json;odata=verbose"
}
});
}
var App = angular.module('App', ['ngRoute'])
App.controller('spRisks', function ($scope, $http) {
var caml = "<View><Query><Where><Eq><FieldRef Name='Owner'/><Value Type='Integer'><UserID/></Value></Eq></Where></Query></View>";
var ownerData = getDataWithCaml("Owners", caml);
ownerData.success(function (data) {
var arrayOfExpressions = [];
for (var i = 0; i < data.d.results.length; i++){
arrayOfExpressions.push(CamlBuilder.Expression().LookupMultiField("Process_x0020_Owner_x0020_Title").EqualTo(data.d.results[i].Title));
}
var newCaml = new CamlBuilder().View().Query().Where().All(arrayOfExpressions).ToString();
newCaml = newCaml.replace(/"/g, '\'');
var jsonData = getDataWithCaml("Risks", newCaml);
jsonData.success(function (jsonDataResults) {
$scope.$apply(function(){$scope.Risks = jsonDataResults.d.results;});
});
});
});
function replaceAll(string, find, replace) {
return string.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}
</script>
One very cool thing that you should learn about angular is that if a controller is on a child element underneath another controller, then it inherits the values of the parent into its scope. It does this through prototypal inheritance. This is worth reading up on, but it basically means that any changes you make to the child scope will not modify the parent scope, so you aren't going to corrupt anything (you can still call methods on the parent scope which can do corrupting for you. And I'm sure you can imagine other ways of interfering with the parent scope, but hopefully you see my point). So if you have:
<div ng-controller="Alpha">
<div ng-controller="Beta"/>
<div ng-controller="Beta"/>
<div ng-controller="Beta"/>
</div>
Then you have three instances of the "Beta" controller, and all of them have a parent scope created by the function "Alpha." So let's say you write the controller for alpha, like so:
function Alpha($scope) {
$scope.title = "Snow White and the Seven Dwarves";
$scope.dwarves = ['Sleepy','Sneezy','Dopey','Bashful',
'Grumpy','Doc','Happy'];
}
Then, in all three instances of "Beta", you gain access to that parent:
function Beta($scope) {
// This will write out "Snow White and the Seven Dwarves".
console.log($scope.title);
}
Now, Beta can always manipulate title, and within its own scope, title will change without affecting the other siblings. If it added a dwarf to the collection, though, then.. well... another dwarf would appear.
ng-repeat is an easy way to create lots of child scopes and then initialize each with a variable:
<div ng-controller="Alpha">
<div ng-repeat="dwarf in dwarves"/>
</div>
So each repeated div tag has its own child scope with the variable dwarf already set. It also has access to the title and even the dwarves collection.
Neat.
You can also attach to it another controller:
<div ng-controller="Alpha">
<div ng-controller="Beta" ng-repeat="dwarf in dwarves"/>
</div>
In which case, in addition to access to dwarf, dwarves, and title, it also runs the function Beta() in order to initialize whatever it needs to initialize.
I've attached a jsfiddle for you, so you can play around with a simple example:
https://jsfiddle.net/p6e0wr1y/
I hope this helps with your specific implementation. If you need me to address your stuff specifically, I will, but I'd like this answer to be valuable to anyone who finds themselves in a similar predicament.
I am using Angular and TingoDB (Mongo) inside Node Webkit for a single page application. However I have a strange problem that I have been unable to resolve.
When I use an object literal (option 2) the data displays correctly in the html page. However changing the code to return data from the database (option 1) the results do not appear on the html page. I have converted both styles of data into the a JSON string to prove consistency and then using the angular.fromJSON to return an object. Both methods return the same JSON string in console.log and before anyone asks I have either Option 1 or Option 2 commented out so both are not running concurrently.
I have copied the JSON string based on the data passed from TingoDB into the console.log and re-entered it into the code below to ensure that no differences between the 2 versions of the data existed without changing any other code, but the problem still persists.
Can anyone shed light on why this occurs and how to fix it?
var app = angular.module('myApp', []);
var Engine = require('tingodb')(),
assert = require('assert');
var db = new Engine.Db('./db', {});
var collection = db.collection("clean.db");
app.controller('tingoDataCtrl', ['$scope', function($scope) {
function getData(callback) {
//Option 1
collection.find().toArray(function(err, docs){
callback (JSON.stringify(docs));
});
//Option 2
var docs = [
{name:"tingo1", description:"56",_id:2},
{name:"tingo2", description:"33",_id:3},
{name:"tingo3", description:"22",_id:4},
{name:"tingo4", description:"76",_id:5},
{name:"tingo5", description:"99",_id:6}
];
callback (JSON.stringify(docs));
}
function info(b) {
// I'm the callback
console.log(b);
$scope.items = angular.fromJson(b)
}
getData(info);
}]);
And the Html
<body ng-app="myApp" id="main">
<div class="page page-data ng-scope">
<section class="panel panel-default" ng-controller="tingoDataCtrl">
<div class="panel-heading"><span class="glyphicon glyphicon-th"></span> Tingo Data</div>
<table class="table">
<thead>
<th class="col-md-4">
Name
</th>
<th class="col-md-8">
Description
</th>
<th class="col-md-8">
ID
</th>
<th></th>
<tr>
</tr>
</thead>
<tbody>
<!-- <tr class="reveal-animation" ng-repeat="item in items | filter:query"> -->
<tr ng-repeat="item in items | filter:query">
<td>{{item.name}}</td>
<td>{{item.description}}</td>
<td>{{item._id}}</td>
</tr>
</tbody>
</table>
</section>
</div>
<script src="js/tingo_problem.js"></script>
</body>
TingoDB is an asynchronous API which will work in the background without stop your app. This means that a syncronous code have no time to wait for an answer and in return it gives undefined.
In your case, you have done a asynchronous call, and it returns correctly the answer to the memory, but too late, the DOM have been updated with undefined already even if your javascript has the data (try console.log to see that it was there).
Angular has a way to be forced to update again the DOM with the new elements of the controller. it is called $apply. And the best way to use it to avoid unexpected behaviours is:
function info(b) {
// I'm the callback
console.log(b);
$scope.items = angular.fromJson(b);
if (!$scope.$$phase) {
$scope.$apply(); //forces update the view
}
}//$scope is NECESARY to be defined in the controler, avoid using it with "ControlerAs"
I'm new to AngularJS and I don't know how to accomplish a task. In my system I have a database with two tables: "Customers" and "Offices". This is a 1:N relation. In my HTML page I have a list (actually is a table) that contains info about the customers (info extracted from the "Customers" table). For each row of the table, you can find a button. If you click on that button some infos about the offices of THAT customer are loaded from the database.
The first part is quite simple. This is the Angular service that loads customers info:
angular.module("app").factory("Customer", ["$resource",
function($resource){
return $resource("/customers/list",
{format:'json'},
{
find: {
method:'GET'
}
});
}]);
This is the Angular controller that exposes an array of customers:
angular.module("app").controller("customersController", ["Customer", "$scope",
function (Customer, $scope){
var customers = new Array();
var metacustomers = Customer.find(function(){
for(var i=0; i<metacustomers.results.length; i++){
customers[i] = new Object();
customers[i].customerName = metacustomers.results[i].customer_name;
customers[i].customerID = metacustomers.results[i].customer_ID;
}
$scope.customers = customers;
});
}]);
And this is the part of the view that shows info:
<table>
<thead>
<th></th>
<th></th>
<th></th>
</thead>
<tr data-ng-repeat="customer in customers | filter:query">
<td>
+
</td>
<td>
<strong>{{customer.customerName}}</strong>
</td>
<td>
<div>
<a title="Modify customer" href="/customers/post/{{customer.customerID}}">
</a>
<a title="Delete customer" href="/customers/delete/{{customer.customerID}}">
</a>
</div>
</td>
</tr>
</table>
All of this looks like:
The problem arrives with the second task. When I click on the "+" button I must load the offices infos about THAT customer (the customer on the same row of the button). I need the customerID to retrieve these infos and I have it. But, how can I say to Angular to load exactly the info belongs to the right customer? I don't know how to model this situation. I need your help. Thank you in advance.
You can pass the customer to the ng-click directive like so:
+
And then create an expand function in your controller which takes a customer as its input. Something like this:
$scope.expand = function(customer){
//fetch the customer
};
Simple html:
<table class="table table-condensed">
<tr data-ng-repeat="customer in customers" data-ng-class="customerSelectedClass(customer)">
<td>
{{customer.Name}}
</td>
</tr>
</table>
In my controller - two functions to select customer and return proper class to highlight a table row:
$scope.customerSelectedClass = function (customer) {
if (customer == $scope.selectedCustomer) {
console.log('returing info for ' + customer.Name);
return "info";
}
return "";
};
$scope.selectCustomer = function (customer) {
console.log('selecting ' + customer.Name);
$scope.selectedCustomer = customer;
}
I noticed that when I click on a customer link, customerSelectedClass function executes twice. selectCustomer function on ng-click directive executes once, as it should. Angular is only included once on the page. I wonder if this is a bug in Angular or something that I am doing wrong?
Behind the scenes, angular is setting up a $watch on the function that is resolving the class name. Because angular uses dirty checking to see if there has been a change, this method will be called twice during the $digest cycle. This is ok.
I would suggest that you don't add this code the the controller though, because if you are managing many css classes, you could be adding a lot of unnecessary code. Try something like this instead:
<table class="table table-condensed">
<tr data-ng-repeat="customer in customers" data-ng-class="{'info': customer == selectedCustomer}">
<td>
{{customer.Name}}
</td>
</tr>
</table>
Then, there is no need for a controller function customerSelectedClass. This will only add the info class if the right-hand side of the : resolves to true. And there is no problem resolving the correct customer in the ng-repeat.
Hope this helps.