Need to reverse a repeat region - firebase

I have a firebase element that is pulling in the last 5 items
<firebase-element id="base" location="https://mydb.firebaseio.com/mydata" data="{{items}}" keys="{{keys}}" limit="5" ></firebase-element>
That is bound to this repeat region
<template repeat="{{id in keys}}">
<x-chat-list id="chatList" username="{{items[id]['uuid']}}" text="{{items[id]['text']}}" ></x-chat-list>
</template>
I simply need to reverse the order of the repeat region.

I think you just need to observe the array and reverse it (or store the reversed values in another attribute)
Ex :
keysChanged : function() { this.keys.reverse(); }
If the firebase-element sometimes changed the values in the array without triggering the keysChanged function, you can also use the observe object

Just add a custom Polymer expression, e.g.:
PolymerExpressions.prototype.revArray = function(a) {
return a.reverse();
}
and pipe your data to it:
<template repeat="{{id in keys | revArray}}">
Now you can use this anywhere since the expression handler is global.

Related

Vectorized Operation in R causing problems with custom function

I'm writing out some functions for Inventory management. I've recently wanted to add a "photo url column" to my spreadsheet by using an API I've used successfully while initially building my inventory. My Spreadsheet header looks like the following:
SKU | NAME | OTHER STUFF
I have a getProductInfo function that returns a list of product info from an API I'm calling.
getProductInfo<- function(barcode) {
#Input UPC
#Output List of product info
CallAPI(barcode)
Process API return, remove garbage
return(info)
}
I made a new function that takes my inventory csv as input, and attempts to add a new column with product photo url.
get_photo_url_from_product_info_output <- function(in_list){
#Input GetProductInfo Output. Returns Photo URL, or nothing if
#it doesn't exist
if(in_list$DisplayStockPhotos == TRUE){
return(in_list$StockPhotoURL)
} else {
return("")
}
}
add_Photo_URL <- function(in_csv){
#Input CSV data frame, appends photourl column
#Requires SKU (UPC) assumes no photourl column
out_csv <- mutate(in_csv, photo =
get_photo_url_from_product_info_output(
getProductInfo(SKU)
)
)
}
return (out_csv)
}
#Call it
new <- add_Photo_URL(old)
My thinking was that R would simply input the SKU of the from the row, and put it through the double function call "as is", and the vectorized DPLYR function mutate would just vectorize it. Unfortunately I was running into all sorts of problems I couldn't understand. Eventually I figured out that API call was crashing because the SKU field was all messed up as it was being passed in. I put in a breakpoint and found out that it wasn't just passing in the SKU, but instead an entire list (I think?) of SKUs. Every Row all at once. Something like this:
#Variable 'barcode' inside getProductInfo function contains:
[1] 7.869368e+11 1.438175e+10 1.256983e+10 2.454357e+10 3.139814e+10 1.256983e+10 1.313260e+10 4.339643e+10 2.454328e+10
[10] 1.313243e+10 6.839046e+11 2.454367e+10 2.454363e+10 2.454367e+10 2.454348e+10 8.418870e+11 2.519211e+10 2.454375e+10
[19] 2.454381e+10 2.454381e+10 2.454383e+10 2.454384e+10 7.869368e+11 2.454370e+10 2.454390e+10 1.913290e+11 2.454397e+10
[28] 2.454399e+10 2.519202e+10 2.519205e+10 7.742121e+11 8.839291e+11 8.539116e+10 2.519211e+10 2.519211e+10 2.519211e+10
Obviously my initial getProductInfo function can't handle that, so it'll crash.
How should I modify my code, whether it be in the input or API call to avoid this vectorized operation issue?
Well, it's not totally elegant but it works.
I figured out I need to use lapply, which is usually not my strong suit. Initally I tried to nest them like so:
lapply(SKU, get_photo_url_from_product_info_output(getProductInfo())
But that didn't work. So I just came up with bright idea of making another function
get_photo_url_from_sku <- function(barcode){
return(get_photo_url_from_product_info_output(getProductInfo(barcode)))
}
Call that in the lapply:
out_csv<- mutate(in_csv, photocolumn = lapply(SKU, get_photo_url_from_sku))
And it works great. My speed is only limited by my API calls.

In Cypress how to count a selection of items and get the length?

I'm starting to learn Cypress. I have a 4 row table (with a class of datatable). I can verify the number of rows this way:
cy.get('.datatable').find('tr').each(function(row, i){
expect(i).to.be.lessThan(4)
})
This is fine, but it seems awkward, since I just want to count the length and don't really need to access the stuff in the rows, and I assume it's faster to do one thing than do 4 things.
If I log the selection (not sure what else to call it):
cy.log(cy.get('.datatable').find('tr'))
it comes out as [object Object] and I'm not quite sure how to deconstruct that, which suggests to me that I'm thinking about this all wrong.
If I try:
expect(cy.get('.datatable').find('tr')).to.have.lengthOf(4)
I get AssertionError: expected { Object (chainerId, firstCall) } to have a property 'length'
If I try:
expect(Cypress.$('.datatable > tr')).to.have.lengthOf(4)
I get AssertionError: expected { Object (length, prevObject, ...) } to have a length of 4 but got 0 so at least it has a length here?
If I log that method of selection I get Object{4}. I'm not sure where to go from here. It seems like this would be a very common thing to deal with.
Found a solution, This works to check a count of items:
cy.get('.datatable').find('tr').should('have.length', 4)
This does not work with the Cypress.$() method of notation.
Reference: https://docs.cypress.io/guides/references/assertions.html#Length
You can also get the length of a selection of items through its property, for example:
cy.get('.datatable').find('tr').its('length').should('eq', 4)
cy.get('.datatable').find('tr').its('length').should('be.gte', 4)
In addition to should('have.length', 4)
I tested with Cypress version 3.1.0 and 3.2.0.
if you want more flexible and have a dynamic result use this.
cy.get('.listings-grid')
.find('.listing')
.then(listing => {
const listingCount = Cypress.$(listing).length;
expect(listing).to.have.length(listingCount);
});
One option is to use "have.length" ...
cy.get('.datatable tr').should('have.length', 4)
...another option is to use should
cy.get('.datatable tr').should(($tr) => {
expect($tr).to.have.length(4)
})
...or then (synchronous queries)
cy.get('.datatable').then(($table) => {
// synchronously query to find length of elements
expect($table.find('td').length).to.equal(4)
})
From the cypress API docs .should() section, using an arrow function:
cy.get('.datatable').find('tr').should(($listOfElements) => {
expect($listOfElements).to.have.length(4)
// any other assertions, for example the below one
// expect($listOfElements).to.have.any.keys('key1', 'key2')
})
This approach will allow you to use Chai BDD notation and assert more than one thing on your list of elements.
cy
.get('ul[data-qa="qa-navbar"] li') // selector
.should('have.length', 5) // Assertion
My use case was to compare that, say no. of "i" icons on the page should match the no. of table rows. So, this solution worked for it i.e. when I wanted to compare the no. of elements of one selector vs the other
cy.get('first element').its('length').then((val)=>{
cy.get('second element).its('length').should('eq',val)
})
Writing then after its captures the requested property (in this case, length) and within the first then block, we do a compare by getting the length of the second element
.children (selector(byId, class, custom attribute) yields DOM
elements and retry untill defaultCommandTimeout exceeds.
cypress config defaultCommandTimeout
once DOM elements exists and yielded added length assertion.
<ul data-qa="qa-navbar">
<li>Home</li>
<li>About</li>
<li>Services</li>
<li>Our Team</li>
<li>Contact Us</li>
</ul>
cy
.get('[data-qa="qa-navbar"]') // selector
.children() // get direct decendents
.should('have.length', 5); // add assertion to have lenght of 5
to get the length you need to use cypress commands:
cy.get('[ng-repeat="item in catalog"]').then(($el) => {
const itemCount = Cypress.$($el).length;
cy.log(itemCount)
})
- In the element locator "aria-setsize" property to find the "number of items in the current set of listitems or treeitems" can be used.
- Within ".then" function, for the previously yielded element. Use ".length" jquery as below.
- To find the list of: Best Sellers in Computers & Accessories, in "Amazon.in" home screen.
it('test', () => {
cy.visit('https://www.amazon.in/ref=nav_logo')
cy.wait(3000)
cy.get('#desktop-5 li[aria-setsize]')
.then(($el) => {
const count= $el.length
cy.log(count)
})
})
Body variable is already resolved as you're in .then() part of the promise:
cy.get("body").then($body => {
cy.log($body.find(".datatable tr").length);
});`

Handlebars Using #root in Custom Helper

I have a scenario where I am trying to access a separate element in my custom helper from within a nested for loop. When I use root outside my for loop I don't have any issues, but I can't seem to use #root within my custom helper. I thought maybe ../ would work, but it appears that is only be moving up to the parent element, not a one that is separate
Here are my two objects:
category //Object being looped through
categoryQuery //Query object being compared to looped values
Here is my view (looping through ID's and then apply selected to the ID attached to categoryQuery:
{{#category}}
<option value="{{this.categoryId}}"{{selected this.categoryId #root.categoryQuery}}>{{this.categoryName}}</option>
{{/category}}
Preselected value if the values match:
/Preselect option value that is associated with edited record
hbs.registerHelper('selected', function(option, value){
if (option === value) {
return 'selected';
} else {
return '';
}
});
Updated:
when adding console.log('Option : ' + option + ' Value : ' + value); into the else statement of my registered helper, I receive the following, which shows that it isn't an issue that #root.category isn't pulling in the value, but it isn't equating correctly.
For example:
Option : 1 Value : 2
Option : 2 Value : 2
Option : 1 Value : undefined
I determined that the root cause of the issue was the strictness in the comparison operator. When changed to == I was able to correctly identify the ID's that matched

CouchDB View with 2 Keys

I am looking for a general solution to a problem with couchdb views.
For example, have a view result like this:
{"total_rows":4,"offset":0,"rows":[
{"id":"1","key":["imported","1"],"value":null},
{"id":"2","key":["imported","2"],"value":null},
{"id":"3","key":["imported","3"],"value":null},
{"id":"4","key":["mapped","4"],"value":null},
{"id":"5,"key":["mapped","5"],"value":null}
]
1) If I want to select only "imported" documents I would use this:
view?startkey=["imported"]&endkey=["imported",{}]
2) If I want to select all imported documents with an higher id then 2:
view?startkey=["imported",2]&endkey=["imported",{}]
3) If I want to select all imported documents with an id between 2 and 4:
view?startkey=["imported",2]&endkey=["imported",4]
My Questtion is: How can I select all Rows with an id between 2 and 4?
You can try to extend the solution above, but prepend keys with a kind of "emit index" flag like this:
map: function (doc) {
emit ([0, doc.number, doc.category]); // direct order
emit ([1, doc.category, doc.number]); // reverse order
}
so you will be able to request them with
view?startkey=[0, 2]&endkey=[0, 4, {}]
or
view?startkey=[1, 'imported', 2]&endkey=[1, 'imported', 4]
But 2 different views will be better anyway.
I ran into the same problem a little while ago so I'll explain my solution. Inside of any map function you can have multiple emit() calls. A map function in your case might look like:
function(doc) {
emit([doc.number, doc.category], null);
emit([doc.category, doc.number], null);
}
You can also use ?include_docs=true to get the documents back from any of your queries. Then your query to get back rows 2 to 4 would be
view?startkey=[2]&endkey=[4,{}]
You can view the rules for sorting at CouchDB View Collation

Flex mobile - How do I move to the next data in List.selectedItem when moving to next page?

When I move page01 to page02, I pass the same data along with it using the following code:
navigator.pushView(Page02, data);
How do I move to page02 with passing the next row of data (instead of the same data)?
In other word, how to increment to the next row of data with pushView?
Thanks.
If you have access to the List component which displays the data you want to pass into views, you can do something like this:
myList.dataProvider[myList.selectedIndex+1]
You'll want to do some checking to make sure that you're trying to reference an index that actually exists:
var mySelectedObject :Object;
if(myList.selectedIndex+1 < myList.dataProvider.length){
mySelectedObject = myList.dataProvider[myList.selectedIndex+1]
} else {
// do some other behaviour; such as selecting the first one in the list
mySelectedObject = myList.dataProvider[0]
}
navigator.pushView(page02, mySelectedObject );

Resources