After the initial call to get the list of items (see below), I need get select the first item and get more details from my database. So after the items load into my select input I need to :
Highlight the first item in listbox
Pass that first itemID to DB to fetch the details of that item.
How can I do all of this within my initial page load?
<!DOCTYPE html>
<html>
<head>
<script src="Scripts/angular.js"></script>
<script src="Scripts/angular-resource.js"></script>
<script>
var IM_Mod_app = angular.module('IM_ng_app', []);
IM_Mod_app.controller("IM_Ctrl", function ($scope, $http) {
var PlaId = "DFC";
$http({
method: 'GET',
url: 'http://xxx/api/ItemMaintenance/GetAllFilteredItems',
params: { PlaId: PlaId }
}).then(function successCallback(response) {
$scope.items = response.data;
}, function errorCallback(response) { });
});
</script>
</head>
<body ng-app="IM_ng_app">
<table ng-controller="IM_Ctrl">
<tr>
<td>
#*<select ng-model="itm" size="10" ng-options="itm.ITEM_ID for itm in items" ng-class="{selected: $index==0}" ng-change="onItemSelected(itm.ITEM_ID)">*#
#*<select ng-model="itm" size="10" ng-options="itm.ITEM_ID for itm in items track by itm.ITEM_ID" ng-selected="$first" >*#
<select ng-model="itm" size="10" ng-options="itm.ITEM_ID for itm in items track by itm.ITEM_ID" ng-init="items[0].ITEM_ID">
<option value="" ng-if="false"></option>
</select>
</td>
</tr>
</table>
</body>
</html>
Your ng-init isn't working as you expect because your array does not have any data when the page loads. Instead, it has to complete the $http call before any of the data is available. This just means that you need to finish your work when your $http call comes back, (in the .then).
Your updated AJAX call might look like this
$http({
method: 'GET',
url: 'http://xxx/api/ItemMaintenance/GetAllFilteredItems',
params: { PlaId: PlaId }
}).then(function successCallback(response) {
$scope.items = response.data;
//Initial the select box
$scope.itm = $scope.items[0];
//Get the details
getSelectedItemDetails();
}, function errorCallback(response) { });
function getSelectedItemDetails() {
$http({}) //whatever API endpoint to get the details
.then(function (response) {
// do something with the data. Maybe extend $scope.itm?
})
}
Moving forward, I discourage using ng-init. Instead, just initialize the value of your variables in your javascript. Because of angular's two-way binding, any updates to the value from the javascript will make it to the HTML.
Try initialising $scope.itm
Let's say I have
<select ng-model="whatever">
<option value="hello">bye</option>
<option value="hello2">..</option>
</select>
If you initialise $scope.whatever = "hello" bye will be displayed in the select
Related
Ok so I am very new to Angular, only been playing with it for three days now. I am running into an issue when trying to filter a table I created based on the value of a "select option" in another controller. Basically I have one controller that performs a REST call to populate a "select" menu dynamically. Then I have another controller that makes a separate REST call to populate a table. What I am trying to do is filter the table based off the "value" from the "selected" option. For example if I choose the "option" with a value of "2", the table would filter to only show results with an "ID" of "2". I may be going about this in a completely wrong way but from what I am reading I need to create a "service" to store the "value" of the "option" so that I can reference it in the controller that populates the table. If anyone could provide some incite on how to go about doing this I would greatly appreciate it. Please see my code bellow...
Angular Code
angular.module('restCalls',[])
// Controller for Project REST Call
.controller('displayProj',function($scope, $http) {
$http({type: "GET", url:"http://my_api_call/", headers: { "ACCEPT": "application/json;odata=verbose"}})
.success(function(data) {
$scope.results = data.d.results;
$scope.projects = [];
for(i=0; i < data.d.results.length; i++) {
$scope.projects.push({name: data.d.results[i].Title , id: data.d.results[i].Id});
};
$scope.getSelectedOption = function(value) {
console.log($scope.selectedProject.id);
};
});
})
// Controller for ChargeCode REST Call
.controller('displayCC',function($scope, $http) {
$http({type: "GET", url:"http://my_api_call/", headers: { "ACCEPT": "application/json;odata=verbose"}})
.success(function(data) {
$scope.results = data.d.results;
$scope.projects = [];
for(i=0; i < data.d.results.length; i++) {
$scope.projects.push({id: data.d.results[i].Master_x0020_ID, cc: data.d.results[i].Title, name: data.d.results[i].deltek_x0020_name});
}
})
});
HTML Code
<div data-ng-app="restCalls" class="ng-scope">
<div id="project_menu_select" data-ng-controller="displayProj" class="ng-scope">
<p class="ng-binding">ID of selected project is: {{selecteProject.id}} </p>
<select data-ng-model="selectedProject" data-ng-options="project.name for project in projects" class="ng-pristine ng-valid ng-empty form-control ng-touched ng-untouched" data-ng-change="getSelectedOption()">
</select> </div>
<div id="charge_codes_table" data-ng-controller="displayCC" class="ng-scope">
<table class="table table-striped">
<thead>
<tr>
<th>Project ID</th>
<th>Charge Code</th>
<th>Deltek Name</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="project in projects">
<td data-ng-if="project.id == (option value)">{{project.id}}</td>
<td data-ng-if="project.id == (option value)">{{project.cc}}</td>
<td data-ng-if="project.id == (option value)">{{project.name}}</td>
</tr>
</tbody>
</table>
</div>
</div>
Anyway you have both table and select option in one page. Better to use single controller for both.
You can also use common parent controller for both of these controllers.
OR
You can use $rootScope to share the variables. Set as $rootScope.selectedValue = 2 from one controller and then you can access this as $rootScope.selectedValue from another controller.
OR
You can use services to share the functions and variables as follows,
app.service("shared", function () {
var selectedOption = {};
return {
getSelectedOption: function () {
return selectedOption;
},
setSelectedOption: function (value) {
selectedOption = value;
}
};
});
When I call $scope.remove in the html it calls the rerender function then automatically updates the data in the html.
When I call $scope.post it calls the rerender function and logs the new data. However, it doesn't automatically rerender the html. I have to refresh the page in order to see the up to date data.
I've looked into using $apply but I'm puzzled how it's updating for remove but not post.
Controller:
var updateData = function (resp){
$scope.data = resp.data;
console.log($scope.data);
}
$scope.getEntries = function (){
return $http({
method: 'GET',
url: '/allEntries'
}).then(updateData)
};
$scope.post = function (){
return $http({
method: 'POST',
url: '/newEntry',
data: $scope.entry
}).then(function (resp){
$scope.getEntries();
})
};
$scope.remove = function (opp){
return $http({
method: 'POST',
url: '/deleteEntry',
data: opp
}).then(function (){
$scope.getEntries();
})
}
I'm thinking it might be something to do with having the functions called in different html files but since they both have the same controller I would think that wouldn't be the case.
<html>
<body ng-app = "app">
<div ng-controller = "controller">
<form ng-submit = "post()">
<input type="submit" value="Submit">
</form>
</div>
</body>
</html>`
<html>
<body ng-app = "app">
<div ng-controller = "controller">
<ul>
<li ng-repeat = "job in data" ><input type = "button" ng-click = "remove(opp)" value="Delete"></li>
</ul>
</div>
</body>
</html>`
Indeed, you have two different sections, each with their own controller, and thus each with their own scope:
one which displays the list of items
one which diesn't display anything
You're posting from the section which doesn't display anything, so it refreshes the list in the scope of that section, which still doesn't display anything.
So, in short, both sections don't have the same controller. They have different controller instances, and those instances happen to have the same type. But they're still completely independant from each other.
And actually, re-reading your question, it's actually worse than that. It seems you have two browser tabs or frames opened. You are posting from one of the tabs, and hope that the other one will refresh automatically. That won't happen: the two tabs are completely independant applications.
Hi I want to post item to server, and with each successful addition, automatically add it to DOM with ng-repeat
<div class="" ng-repeat="book in books" >
<div id="eachBook">{{book.title}}</div>
</div>
to POST the data and also to upload an image file, I use Jquery ajax, and $state.go(".") to reload the current page:
var fd = new FormData();
fd.append("file", bookImage);
$http({
method: 'POST',
url: "/someurl,
data: fd,
headers: {
'Content-Type': undefined
}
}).success(function(Image){
var book_obj = {
bookTitle: bookTitle,
bookImage: Image._id
};
$http.post("url to owner book", book_obj)
.success(function(data){
$scope.bookImage = data.bookImage;
$timeout(function(){
alert("success", "successfully added your book");
$state.transitionTo('book', {}, { reload: true });
},2000);
})
})
The problem is with first addition, the DOM is still empty, and even though I use $state to reload the page, it still not working for the first addition. In the end I need to refresh the page manually by clicking refresh.
after the first addition, it works fine. With each book added, it automatically added to DOM..
Any idea how to automatically start the first one without manually rendering the page? using $timeout to delay the refresh has no effect.
Is it not just a simple post to list on success?
var app = angular.module('myApp', []);
app.controller('bookCtrl', function($scope, $http, $timeout) {
$scope.init = function(){
$scope.title = 'initial book?'
postBook();
};
$scope.books = [];
$scope.post = function() {
postBook();
};
function postBook(){
if (!$scope.title) return;
// timeout to simulate server post
$timeout(function() {
$scope.books.push({title:$scope.title});
$scope.title = null;
}, 1000);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="bookCtrl" ng-init="init()">
<div class="" ng-repeat="book in books">
<div class="eachBook">{{book.title}}</div>
</div>
<input type="text" ng-model="title" /><button ng-click="post()">save</button>
</div>
EDIT: Not sure why your DOM isn't ready but how about ng-init to accomplish an initial book post?
I'm writing a small test application where I can retrieve my customers from a parse.com database.
I have the following form in html
...
<body ng-app="myApp">
<div ng-controller="CustomerController">
<button ng-click="getCustomers()">Get customers</button>
<ul>
<li ng-repeat="customer in customers">{{ customer.name }}</li>
</ul>
</div>
</body>
...
My angular app is the following:
Module
var app = angular
.module('myApp', ['ngResource'])
.constant('myConfig', {
'api_url': 'https://api.parse.com/1/classes/',
'parse_application_id': 'xxxxxxxxxxxxx',
'parse_rest_api_key': 'xxxxxxxxxxxxx'
});
Factory
app.factory('CustomersService', function($resource, myConfig) {
return $resource(myConfig.api_url + 'Customer', {}, {
query: {
method: 'GET',
isArray: false,
headers: {
'X-Parse-Application-Id': myConfig.parse_application_id,
'X-Parse-REST-API-Key': myConfig.parse_rest_api_key
}
},
create: {
method: 'POST',
headers: {
'X-Parse-Application-Id': myConfig.parse_application_id,
'X-Parse-REST-API-Key': myConfig.parse_rest_api_key
}
}
})
});
Controller:
app.controller('CustomerController', function($scope, CustomersService, CustomerService) {
$scope.getCustomers = function() {
CustomersService.query().$promise.then(function(result) {
$scope.customers = result.results;
});
};
});
So when I click my button, everything works like it should.
But I also want to add a filter by name when I want to retrieve customers from the database.
When I execute the following in Postman
https://api.parse.com/1/classes/Customer?where={"name":"aaaaa"}
this works and only gets the customer with the name "aaaaa". So I know that the syntax is OK.
So I will add a textbox where the user can enter a customername and after that I want to click on the search button.
But how can I manage the ?where={"name":"aaaaa"} into the angular stuff when I click the button? I also want to expand the filter with other columns from that customer.
Something like this should work (assuming everything goes in the where object)
Add some search fields that bind to a scoped object's properties. We'll call it search
<label for="search_name">Name</label>
<input type="text" ng-model="search.name" name="name" id="search_name">
<label for="search_city">City</label>
<input type="text" ng-model="search.city" name="city" id="search_city">
Then you can execute the query action with
CustomersService.query({where: $scope.search}).$promise...
That should create a query param like
?where=%7B%22name%22%3A%22aaaaa%22%2C%22city%22%3A%22London%22%7D
which is the URI encoded value
?where={"name":"aaaaa","city":"London"}
I am trying to grasp the idea behind angular and ran into my first obstacle involving accessing data from outside the scope (the app?)
Here is a very simple example of what I'm trying to do:
HTML:
<div class=logo>
<a href='/refresh'>Refresh</a>
</div>
<div ng-app ng-controller="threadslist">
<div class='thread_list_header'>
<table class='thread_list_table'>
<tr class='table_header'>
<!--1--><td class='table_c1'></td>
<!--2--><td class='table_c2'>{{name}}</td>
<!--3--><td class='table_c3'>Cliq</td>
<!--4--><td class='table_c4'>Last Poster</td>
<!--5--><td class='table_c5'><a class="clickme">Refresh</a></td>
</tr></table>
</div>
<table class='thread_list_table' >
<tr class="thread_list_row" ng-repeat="user in users">
<!--1--><td class='table_options table_c1'></td>
<!--2--><td class='table_subject table_c2' title="">{{user.subject}}</td>
<!--3--><td class='table_cliq table_c3'></td>
<!--4--><td class='table_last table_c4'><span class="thread_username"><a href=#>{{user.username}}</a></span></td>
<!--5--><td class='table_reply table_c5'><abbr class="thread_timestamp timeago" title=""></abbr></td>
</tr>
</table>
</div>
JS:
function threadslist($scope, $http) {
$scope.name = 'Ricky';
// Initialising the variable.
$scope.users = [];
$http({
url: '/cliqforum/ajax/ang_thread',
method: "POST",
}).success(function (data) {
console.log(data);
$scope.users = data;
});
// Getting the list of users through ajax call.
$('.table_header').on('click', '.clickme', function(){
$http.get('/cliqforum/ajax/ang_thread').success(function(data){
$scope.users = data;
});
});
}
This is the part I can't figure out. My logo is supposed to clear whatever filter is on the current 'user' data. However, it sits outside the scope (and I imagine I shouldn't expand the scope to be the entire page?)
I have read something about scope.$spply but can't quite figure out what I'm supposed to do:
$('.logo').on('click', 'a', function() {
scope.$apply(function () {
$scope.users = data;
});
});
It's not quite necessary that I do it THIS way...I would just like to do what is correct!
Thanks!
and I imagine I shouldn't expand the scope to be the entire page?
Why not? That's definitely the way to do it. Just include the logo into the scope and you can then access it from your application, and use ng-click to add a click handler.
In fact, you should avoid using jQuery click handlers within your application. You could transform your JavaScript like so:
$scope.tableHeaderClick = function() {
$http.get('/cliqforum/ajax/ang_thread').success(function(data){
$scope.users = data;
});
});
Then update the HTML like so:
<tr class='table_header' ng-click="tableHeaderClick()">
it is an angular anti-pattern to include DOM elements in controller. you want to use the ng-click directive to respond to click events
see this plnkr:
http://plnkr.co/edit/KRyvifRYm5SMpbVvWNfc?p=preview