Hi I'm fairly new to Angular so go easy on me.
I have a list of numbers that are popluated from a database. These are coming through fine as list of numbers. I would like to display these numbers in various parts of the webpage rather than in a list. I was wondering if there is a way to access or reference individual entries of the ng repeat response. Or is there another way I can access individual elements of the query .
This is my HTML
<li ng-repeat="x in myData">
{{x.Values}}
</li>
(some html ommited due to formatting)
and This is the controller I am using to populate it
app.controller('customersCtrl', function($scope, $http) {
$http.get("scripts/counts.php").then(function (response) {
$scope.myData = response.data.records;
});
});
so rather than have {{x.values}}
I would like to be able to assign aungular variables to each row.
Thanks.
If you want to access the individual entries, if it's an Object you can simply call it's property:
<li>{{myData.key}}</li>
Or if it's an array:
<li>{{myData[0]}}</li>
Related
Ok, seems that I was having too many issues with the way in which my Angular site is setup, so I put it in a plunker as then anyone can see it.
Original question: Angular retrieve specific data into $scope variable is not working
Plunker
http://plnkr.co/edit/NsE29zjraQp9UeklJBiI?p=preview
My issues are
1. i'm not understanding how to use app.filter
2. Issue with app name
3. forEach with push inside $http.get throws error not defined
The plunker Index.html has the template code loop , app.module.js is root and the device.controller.js is where I'm using controller with $http.get call using json file to fake it.
I was attempting to use the other persons answer so this code
$scope.devices = result.data.Devices; // gives all data ...
Filter I was wondering if this with work
<div ng-repeat="device in devices">
{{ device.DeviceStatus }}
</div>
Then this code I'm not sure it in the correct "place"
seems like i'm not understanding "app"
app.filter('deviceStatus', function () {
return function (status_id) {
var statuses = ['Old Device', 'New Device', 'Activated', 'Unactivated'];
return statuses[status_id];
};
});
Example filter:
<td>{{device.DeviceId | deviceStatus}}</td>
Let me try to understand your issue.
As per your question, it seems that you have problems understanding what app is and how to use filter.
This is the working version of your plunkr. Check this url
app in your project is the ng-app directive. The ng-app directive tells AngularJS that the element is the "owner" of an AngularJS application.
For understanding filter functionality. check the below example.
You were trying to push into $scope.statuses which is not defined yet. So first define $scope.statuses to be an empty array i.e `$scope.statuses = [];
Hope this works for you!`
// To declare a filter we pass in two parameters to app.filter
// The first parameter is the name of the filter
// second is a function that will return another function that does the actual work of the filter
//here app is the module name of your project
app.filter('myFilter', function() {
// In the return function, we must pass in a single parameter which will be the data we will work on.
// We have the ability to support multiple other parameters that can be passed into the filter optionally
return function(input, optional1, optional2) {
var output;
// Do filter work here
return output;
}
});
I am using a backemnd service (parse in this case but that doesn't really matter for this question) and wanted to simply search it. I have a textbox that upon text being entered searches the server and returns an array of matchs.
My next step is to simply display my returned objects nicely in a list. Easy enough with ng-repeat but because the view has already been loaded the UI won't update to reflect the array being loading into the list. Does that make sense?
I was wondering if there was a technique to Refresh the list and show the returned search elements, and hopefully I am not being to greedy here but doing it in a way that looks good and not clunky.
I did a lot of googling with NO luck :( any advice would be amazing.
Without any code provided it is hard to guess what is wrong. Angular has two-way binding, so view should be updated automatically after changing content of an array. If it's not, it means that you probably did something wrong in your code. I present an example code which should work in this case.
Controller
angular.module('moduleName')
.controller('ViewController', ['ViewService', ViewController]);
function ViewController(ViewService) {
var self = this;
self.arrayWithData = [];
self.searchText = "";
// ---- Public functions ----
self.searchData = searchData;
// Function which loads data from service
function searchData(searchText) {
ViewService.getData(searchText).then(function(dataResponse) {
// Clear the array with data
self.arrayWithData.splice(0);
// Fill it again with new data from response
angular.forEach(dataResponse, function(item) {
self.arrayWithData.push(item);
});
});
}
// --- Private functions ---
// Controller initialization
function _initialize() {
self.searchData(self.searchText);
}
_initialize();
}
View
<div ng-controller="ViewController as view">
<input type="text" ng-model="view.searchText" />
<input type="button" value="Search!" ng-click="view.searchData(view.searchText)" />
<!-- A simple ngRepeat -->
<div ng-repeat="item in view.arrayWithData">
<!-- Do what you want with the item -->
</div>
</div>
Conclusion
By using splice() and push() you make sure that reference to your array is not changed. If you are using controllerAs syntax (as in the example), assigning new data with '=' would probably work. However, if you are using $scope to store your data in controller, losing reference to the array is the most probable reason why your code doesn't work.
In my app I do a database call to get a list of elements to display using ng-reat, this works fine. Inside that list is another list. That depends on another DB call.
I'd like to pass an id and repeat an element the number of results I get back and output their data. Something like this:
<div ng-repeat="library in libraries">
<p>Read our books:</p>
<p ng-repeat="book in books">{{book.title}}</p>
</div>
I thought about this:
<p ng-repeat="book in getBooks({library.id}) track by $index">{{book.title}}</p>
this use something like this to trigger the number of repeats and the values:
$scope.getBooks = function(id){
...run my database query using the id...
...update my scope to include the books...
....**magic**...
}
but I'm not sure if that will work and how to update my scope to include the book title. I've used this to repeat an x number of times but not include an updated $scope
Along with Corbin, my solution would be to pre-load the data. Do that with an Angular factory object.
angular.module('appName')
.factory('DataManager', DataManager);
function DataManager($log, $timeout, DataService) {
var mngr, config = getConfig(); // any default values
$log.debug('DataManager Init');
mngr = {
CurrentSearchTerm: null,
Libraries: [],
Abort: abort,
GetData: getData // Function call to get data.
};
// This call is your main ajax call, it could be one call to get the
// full dataset of lib + books in json format. Or multiple calls.
function getData(){
DataService.getData().then(function(response){
// ...parse data, etc...loop and :
mngr.Libraries.push(parsedDataItem);
};
}
return mngr;
}
Inject that into your controller. Then you loop over that data.
<ul>
<li ng-repeat="library in mngr.Libraries">
<!-- now you should have library.Books which was already sent down in the factory payload. -->
</li>
</ul>
Again to make your life a bit easier use a directive, each repeat push it's data into a directive:
<library data="library">
Which allows you to have a nice template and scope into just that one library.
angular('appName').directive('library',function(){
return{
restrict:'E',
replace:true,
templateUrl:'library.view.html',
scope:{
data:'='
},
controller:function($scope,$log){
// Here $scope.data === library from your ngRepeat!
}
};
});
Lastly, if you wanted an ondemand loading of the books, in the directive you can add a method to your DataManager to 'getBooks' for that one library object.
Does that make more sense?
I am seriously having a hard time retrieving nested data from Firebase with AngularJS. I try to save data this way in Firebase, btw I am using Angularfire to save and retrieve data from the database. How can I retrieve the value of foo with ng-repeat? I also find that the documentations is scarce and tutorials are outdated. I like the real time updates and that is why I want to use it. There are no errors in the console btw. Thanks in advance for any suggestions.
--Unique id
--0
--foo:"bar"
--1
--foo:"bar"
Now when I do this in my HTML it gives me back the index number:
<div ng-repeat="(item, id) in list">
<span>{{item}}</span><button ng-click="remove(id)">x</button>
</div>
</div>
But when I do this, it does not give me the values of foo:
<div ng-repeat="(item, id) in list">
<span>{{item.foo}}</span><button ng-click="remove(id)">x</button>
</div>
</div>
Javascript
angular.module("app", ['firebase'])
.controller("ctrl", function ($firebase, $scope) {
var ref = new Firebase('https://testing12344.firebaseio.com/');
var x=[{foo:"bar"}, {foo:"bar"}];
var sync = $firebase(ref);
var list = sync.$asArray();
list.$add(x);
$scope.list = list;
console.log($scope.list);
$scope.remove = function (id){
list.$remove(id);
}
})
As I already commented: Firebase's documentation recommends against building nested data structures; partially because of the reason you encounter. The only time I find myself nesting data structures like this, is when a user is typically "inside" one of these top-level children. In that case the outermost ID is part of the context and I won't need a nested loop, like you do.
That said, you can easily make your code/view work if you ensure it matches the data structure correctly. Since you have a collection (with children 0 and 1) inside a collection (with the generated IDs), you'll need to ng-repeats to reach foo:
<ol>
<li ng-repeat="item in list">
{{item.$id}}
<ol>
<li ng-repeat="child in item">{{child}}</li>
</ol>
</li>
</ol>
A snippet from the output:
1. -Jgv9EmOXmXYNrYPG8jK
1. {"foo":"bar"}
2. {"foo":"bar"}
2. -Jgv9GEXJLnaQmYeYR2u
1. {"foo":"bar"}
2. {"foo":"bar"}
3. -JgvHQ1YJsgF9THdfmd7
1. {"foo":"bar"}
2. {"foo":"bar"}
I also noticed that you're logging console.log($scope.list);, which is a common mistake. By the time that console.log statement executed, the data may not have been loaded from Firebase's servers yet. Sometimes it shows up correctly in your browser's JavaScript console, but sometimes it doesn't.
The proper way to log the data once it is loaded is:
list.$loaded().then(function(list) {
console.log('Initial child count', list.length);
console.log(list[0][0].foo);
});
Note that $loaded will only trigger for the initially downloaded data, not for subsequent updates. If you care about those, you should look into AngularFire's $watch. But to be honest: you should normally not have a need for that. Once you bind your AngularFire data to the view correctly, it should update automatically in most use-cases.
I need some ideas on how to create a search filter in EmberJS where the search results can persist across views. Lets say I have a list of contacts and I filtered the list. Assume this route is called Contacts/Index
Now I have a second route called Contacts/Details. The user will be directed to this route once they select a result from the contact list. Now when they click 'Back To Contacts', I want the previous filter to be still applied instead of showing all the Contacts.
I didn't write any code yet, so I can't provide a JSFiddle. All I can think of now is probably to create a global variable to keep track of the text that is used to filter and apply that when transitioning back to the Contacts/Index view but I'm not sure if it is the right way to do it.
This is just pseudo-code that doesn't really care what your filter type is, but you could apply a filter property to the ContactsIndexController:
App.ContactsIndexController = Ember.ArrayController.extend({
//...
filter: 'name=bro',
filteredContent: function () {
if(this.get('filter')){
return this.get('content').filter//...;
} else {
return this.get('content');
}
}.property('filter')
//...//
});
Whenever you change the filter, make sure to update the filter property:
this.set('filter', 'foo=bar');
Then in your handlebars template you always loop over filteredContent:
{{#each filteredContent}}
{{/each}}
When you transition back and forth between the Contacts inner routes, it should retain the filter when you return to the index.
You can also see how this pattern could be used to take this one step further and manipulate the filter from literally anywhere in the application. If you aren't in that controller's context, you can still update that property and bindings will appropriately render the computed property next time you visit.
From another controller:
this.set('controllers.contacts-index.filter', 'year=20x6')
From a route:
this.controllerFor('contacts-index').set('filter', 'year=20x6')
From a view within the index controller:
this.set('controller.filter', 'year=20x6')
I'm sure you get the idea.
This is, of course, one of several approaches you could take. I prefer this particular pattern.
Hope that helps and good luck!