How do I get the DataSource's length of a ListView?
Suppose I have the following declaration:
const ds = new ListView.DataSource({ rowHasChanged });
...
someObjectsDs = ds.cloneWithRows(someObjectsArray);
I've tried someObjects.length but this returns me undefined.
You can view the amount of rows to be rendered by calling
someObjectsDs.getRowCount()
Official documentation
You can either dig into the datasource object to find the data and grab the length or you can set the data as a property of the component and refer to that:
this.someObjectsArray = someObjectsArray;
someObjectsDs = ds.cloneWithRows(this.someObjectsArray);
Now you will be able to do this.someObjectsArray.length, just make sure you're updating this variable anytime you're updating the datasource.
Related
Is there a way to display a list of objects in a single table cell for ng2-smart-table? I have tried creating a renderComponent but I am getting an empty value. Another question is will the filtering and sorting still work for this?
As I understood , You have a object and you want to display that data in ng2-smart-table.
For that follow this step.
import { LocalDataSource } from 'ng2-smart-table';
source : any = LocalDataSource;
When you call API then you have to set that data in source.
this.apiService.POST({}, 'getProductList').subscribe((res) => {
console.log(res);
this.source = new LocalDataSource(res.data); // Set response as per your res.
});
As you can see I have also set one array and that array has objects of data and I have set in table.
I hope this may help you. :)
I currently have an iron-list within another iron-list. The parent's data comes from a firebase-query element, and the child's data is computed from each parent item. The db structure and code looks a bit like this:
DB: [
category1: [
itemId1: {
price: 10,
title: "title"
}
]
]
<iron-list id="categoryList" items="{{categories}}" multi-selection as="category">
<template>
<div class="category-holder">
<iron-list id="{{category.$key}}" items="{{_removeExtraIndex(category)}}" as="item" selection-enabled multi-selection selected-items="{{selectedItems}}" grid>
<template>
<div class$="{{_computeItemClass(selected)}}">
<p>[[item.title]]</p>
<p>[[item.price]]</p>
</div>
</template>
</iron-list>
</div>
</template>
</iron-list>
After selecting any number of items, the user can tap on a fab to batch edit the price. This is where I'm having issues. I can't figure out how to access the correct child iron-list in order to call list.set...I'm currently trying the following very nasty method:
var categories = this.$.categoryList;
var categoryItems = categories.items;
(this.selectedItems).forEach(function(item) {
var index = item.itemId;
categoryItems.forEach(function(itemList, categoryIndex) {
if (itemList[index]) {
categories.set('item.' + categoryIndex + '.price', 10);
}
}, this);
}, this);
I'm iterating over the selected items in order to extract the item index and then iterating over the parent iron-list data (categoryItems) in order to check if the given item exists in that subset of data. If so, then I use the category index and attempt to call set on the parent iron-list using the given path to access the actual item I want to edit. As expected, this fails. Hopefully I've made myself clear enough, any help would be appreciated!
EDIT #1:
After much experimenting, I finally figured out how to correctly mutate the child iron-list:
(this.selectedItems).forEach(function(item) {
var list = this.$.categoryList.querySelector('#' + item.category);
var index = list.items.indexOf(item);
list.set(["items", index, "price"], 30);
}, this);
A couple of things worth noting. I'm using querySelector instead of the recommended this.$$(selector) because I keep running into a "function DNE" error. But now I have another problem...after calling the function, the value gets updated correctly but I get the following error:
Uncaught TypeError: inst.dispatchEvent is not a function
Here's a picture of the full error message:
I see the light, hopefully someone can help me out!
OK, I'll take a shot at this. I think the following happens, and I guess this based on how dom-repeat works:
var categories = this.$.categoryList;
var categoryItems = categories.items;
You take the variable that the iron-list is based on, but setting one array to another just creates a reference in javascript. As soon as you update categoryItems, you also update this.$.categoryList.items. When you later sets the new value, iron-list will do a dirty check and compare all subproperties, and because they are equal (because ... reference), the iron-list wont update the dom.
What you should do is to make sure it's a totally new copy and the way of doing that is to use JSON.parse(JSON.stringify(myArray)).
Further on, one major flaw I see in your code is that you're using querySelector to select an element, and then manipulate that. What you should do is to use this.categories and only that variable.
So your method should look something like:
// Get a freshly new array to manipulate
var category = JSON.parse(JSON.stringify(this.categories);
// Loop through it
category.forEach(category) {
// update your categoryList variable
}
// Update the iron list by notifying Polymer that categories has changed.
this.set('categories', category);
I'm using Backgrid and I create the Backgrid Object as follows in my Controller:
$.when(recipeRequest).done(function (recipes) {
List.grid = new Backgrid.Grid({
columns: columns, // where columns is defined elsewhere
collection: recipes // recipes is the result of a fetch
})
// Then add it to the Marionette template
}
The above works perfectly and items display as expected
Once the table is displayed we are providing filtering functionality ServerSide as follows:
filterRecipes: function (query) {
// remove any incomplete network requests
_.each(RecipeManager.fetchXhrs, function (r) {
r.abort()
})
// get a filtered set of recipes
var filteredRecipes = RecipeManager.request('recipe:entities', query)
$.when(filteredRecipes).done(function (recipes) {
// this line shows that the result set is being updated as expected with for example 6 results
console.log(recipes)
// setting the new recipe result set to the grid.collection
List.grid.collection = recipes
// here the table rerenders but there are a LOT more results on the table - not 6 as expected
List.grid.render()
})
}
I'm expecting the table to be repopulated with the new collection once the results are returned but my table still shows all the old records.
I'm following the example written here How would I refresh a Backgrid table with new data? So it should redraw the table once the collection has been reset? Or do I need to empty the table first? Any ideas where I might be going wrong?
From backgridjs
Fully reactive. Relevant parts of the grid re-renders automatically upon data changes.
I have not gone through annotated source code but am guessing rerendering is tied to collection events. So, you do not need to explicitly call the render method.
$.when(filteredRecipes).done(function (recipes) {
// this line shows that the result set is being updated as expected with for example 6 results
console.log(recipes)
// setting the new recipe result set to the grid.collection
// considering recipes is backbone collection
// if result is array of objects then List.grid.collection.reset(recipes)
// it should re render the grid
List.grid.collection.reset(recipes.models);
})
Say I'd like to fetch only items that contains keys: "-Ju2-oZ8sJIES8_shkTv", "-Ju2-zGVMuX9tMGfySko", and "-Ju202XUwybotkDPloeo".
var items = new Firebase("https://hello-cambodia.firebaseio.com/items");
items.orderByKey().equalTo("-Ju2-gVQbXNgxMlojo-T").once('value', function(snap1){
items.orderByKey().equalTo("-Ju2-zGVMuX9tMGfySko").once('value', function(snap2){
items.orderByKey().equalTo("-Ju202XUwybotkDPloeo").once('value', function(snap3){
console.log(snap1.val());
console.log(snap2.val());
console.log(snap3.val());
})
})
});
I don't feel that this is the right way to fetch the items, especially, when I have 1000 keys over to fetch from.
If possible, I really hope for something where I can give a set of array
like
var itemKeys = ["-Ju2-gVQbXNgxMlojo-T","-Ju2-zGVMuX9tMGfySko", "-Ju202XUwybotkDPloeo"];
var items = new Firebase("https://hello-cambodia.firebaseio.com/items");
items.orderByKey().equalTo(itemKeys).once('value', function(snap){
console.log(snap.val());
});
Any suggestions would be appreciated.
Thanks
Doing this:
items.orderByKey().equalTo("-Ju2-gVQbXNgxMlojo-T")
Gives exactly the same result as:
items.child("-Ju2-gVQbXNgxMlojo-T")
But the latter is not only more readable, it will also prevent the need for scanning indexes.
But what you have to answer is why want to select these three items? Is it because they all have the same status? Because they fell into a specific date range? Because the user selected them in a list? As soon as you can identify the reason for selecting these three items, you can look to convert the selection into a query. E.g.
var recentItems = ref.orderByChild("createdTimestamp")
.startAt(Date.now() - 24*60*60*1000)
.endAt(Date.now());
recentItems.on('child_added'...
This query would give you the items of the past day, if you had a field with the timestamp.
You can use Firebase child. For example,
var currFirebaseRoom = new Firebase(yourFirebaseURL)
var userRef = currFirebaseRoom.child('users');
Now you can access this child with
userRef.on('value', function(userSnapshot) {
//your code
}
You generally should not be access things using the Firebase keys. Create a child called data and put all your values there and then you can access them through that child reference.
I imagine this is an easy thing to do, but I wasnt able to find the information I was looking for through google. I have popupProperties which is just default stuff. I then call to the service which returns specific overrides depending on the popup. How can I iterate through all of the service's overrides and apply them to the popupProperties?
var popupProperties = getDefaultPopupProperties();
var popupOverrides= popupService.getPopupOverrides(currPopupId);
angular.forEach(popupOverrides, function(popupProperty, propertyName){
//replace defaults with popupData's properties
});
You should have a look at the solution of Josh David Miller which uses the extend method of angular (documentation).
var defaults = {name:'John',age:17,weight:55};
var overrides = {name:'Jack',age:28,color:'brown'};
var props = angular.extend(defaults, overrides);
// result
props: {
name:'Jack',
age:28,
weight:55,
color:'brown'
}
The values are copied in the defaults variable. There is no need of using the return value (var props =).
I presume you mean both functions are returning objects with a number of properties (as opposed to an array).
If so, the following should work - just JavaScript, nothing AngularJS specific:
for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
See this question for more details How can I merge properties of two JavaScript objects dynamically?