enyo animating a listItem - list

I have a 3 listItems and when I click one of them I want the green bar to animate from the right to the left.
But it doesn't behave properly.. When you click nothing happens, when you click a second time (optionaly on an other row) thing just get funky.
Is there a proper solution for this?
http://jsfiddle.net/joopmicroop/6GJs4/
enyo.kind({
name:'main',
classes: "enyo-fit",
components:[
{name:'list', kind:'enyo.List', count:'3', onSetupItem:'itemSetup', components:[
{name:'listItem', kind:'listItem', ontap:'itemTapped'},
]},
],
itemTapped:function(s,e){
console.log('itemTapped',e.rowIndex);
this.$.list.prepareRow(e.rowIndex);
this.$.list.performOnRow(e.rowIndex, function(){ this.animate(); }, this.$.listItem);
this.$.list.lockRow();
this.$.list.renderRow(e.rowIndex);
},
itemSetup:function(s,e){ this.$.listItem.setText('item'+e.index); }
});
enyo.kind({
name:'listItem',
classes:'listItem',
published:{text:''},
create:function(){
this.inherited(arguments);
this.animator = new enyo.Animator({
onStep:enyo.bind(this, function(animObj){
this.$.backBar.applyStyle('width',animObj.value+'%');
}),duration:1000
});
},
components:[
{name:'backBar', classes:'animBar'},
{name:'itemContent', content:''},
],
animate:function(){
if(!this.animator.isAnimating()) this.animator.play({startValue:10, endValue:100});
},
textChanged:function(oldVal){ this.$.itemContent.setContent(this.text); },
});
(new main()).renderInto(document.body);

The biggest problem you have here is that the row ceases to have a node after the call to performOnRow(). The extra call to lockRow() isn't necessary since it's locked automatically. If you want this to work you'll need to use a different method after preparing the row or you'll need to cache the node and operate directly on the node. It's possible you could do it with some CSS animations as you would only need the node long enough to set the new value once and let the browser do the animation.
Forgot to add: Nodes are not actually created until the control is rendered. If you want to perform operations only after a node exists, overload rendered().

Related

Vue3 force reset/clear of keep-alive components

I'm using keep-alive to maintain the state of a multi-step form in Vue3 so users can navigate back and forth as needed.
What I can't figure out, is how to force a clear of the cache. When users complete the form I give them an option to re-start and I currently clear the form submission object and return the users to page 1 of the form but keep-alive is preserving the form state so checkboxes are pre-selected. Is there a call I can make from my reset function to clear the keep-alive cache? Ideally for only some of the form steps, not all.
Hard to do.;) There's no built-in method to clear the keepAlive cache.
Looks like the form is not completely reseted but maybe could be enough to destroy the instance of components wrapped in
Are you using key="x" on the component that's wrapped with ? Like:
<KeepAlive>
<component key="x"/>
</KeepAlive >
reseting the key together with redirecting to 1st page could help.
But also to my mind came an idea that You maybe should re-initialize form initialData
ex:
<script>
const initialState = () => {
return {
name: '',
surename: '',
location: {
name: null,
},
};
};
export default {
data() {
return initialState();
},
methods: {
reset() {
Object.assign(this.$data, initialState());
},
},
};
</script>
let's dive into
https://learnvue.co/tutorials/vue-keep-alive
Found related issue:
https://stackoverflow.com/a/71766767/10900851
https://github.com/vuejs/vue/issues/6259#issuecomment-436209870
I actually ended up using an entirely different method and thought I would put it here in case it is of use to someone else.
I found it here: https://michaelnthiessen.com/force-re-render/
Basically, a reset of a component can be forced by changing its key value. This has the added benefit of letting you selectively force a re-render of any number of child components.
In the parent.
<PageOne :key="page_one_key">
<script>
export default {
...
data() {
return {
page_one_key: 0,
}
},
...
methods: {
myreset(){
this.page_one_key += 1;
}
}
}
</script>
If there are downsides to this approach I would love to know but it seems to work perfectly - allows back/forwards navigation of my form and selective resetting of the cached components.
It is also simple to implement.

cypress .next at end of list yields '' but I need to break instead

I am writing Cypress tests for an application that has a dynamic group/list of items. Each item has a details link that when clicked creates a popup with said details. I need to close that popup and move to the next item in the group.
I first tried to use the .each() command on the group and then would .click({multiple:true}) the details but the popup would cover the the next click. Adding {foce:true} does allow all of the popups to display but I don't think that is in the spirit of how the application should function.
My latest attempt has been to create a custom command using .next() to iterate through the group. This works but when .next() reaches the end of the group it yields "" and so the test ultimately fails.
The actual error I get is:
Expected to find element: ``, but never found it. Queried from element: <div.groups.ng-star-inserted>
the .spec.ts
describe('Can select incentives and view details', () => {
it('Views incentive details', () => {
cy.optionPop('section#Incentives div.groups:first')
})
})
the index.ts
Cypress.Commands.add('optionPop', (clickable) => {
cy.get(clickable).find('[ng-reflect-track="Estimator, open_selection_dial"]').click()
cy.get('mat-dialog-container i.close').click()
cy.get(clickable).next().as('clicked').then(($clicked) => {
//fails at .next ^ because '' is yielded at end of list
cy.wrap($clicked).should('not.eq','')
})
cy.optionPop('#clicked')
})
You basically have the right idea, but it might work better in a plain JS function rather than a custom command.
function openPopups(clickables) {
if (clickables.length === 0) return // exit when array is empty
const clickable = clickables.pop() // extract one and reduce array
cy.wrap(clickable)
.find('[ng-reflect-track="Estimator, open_selection_dial"]').click()
cy.get('mat-dialog-container i.close')
.should('be.visible') // in case popup is slow
.click()
// wait for this popup to go, then proceed to next
cy.get('mat-dialog-container')
.should('not.be.visible')
.then(() => {
openPopups(clickables) // clickables now has one less item
})
}
cy.get('section#Incentives div.groups') // get all the popups
.then($popups => {
const popupsArray = Array.from($popups) // convert jQuery result to array
openPopups(popupsArray)
})
Some extra notes:
Using Array.from($popups) because we don't know how many in the list, and want to use array.pop() to grab each item and at the same time reduce the array (it's length will control the loop exit).
clickables is a list of raw elements, so cy.wrap(clickable) makes the individual element usable with Cypress commands like .find()
.should('be.visible') - when dealing with popup, the DOM is often altered by the click event that opens it, which can be slow relative to the speed the test runs at. Adding .should('be.visible') is a guard to make sure the test is not flaky on some runs (e.g if using CI)
.should('not.be.visible').then(() => ... - since you have some problems with multiple overlapping popups this will ensure each popup has gone before testing the next one.

How to get current line on change in slate.js

How does one get the current line, or the currently edited node, within the onChange or onKeyDown methods in Slate.js?
I'm trying to add an updatedAt or createdAt parameter in the data attribute for a particular line.
Here's a proof of concept for what I'm trying to do:
onChange = ({ value }) => {
return value.document.nodes.reduce((change, node) => {
return change.setNodeByKey(node.get("key"), {
data: {
createdAt: new Date(),
...node.get("data").toJS(),
},
});
}, value.change()).value;
}
This loops through every node and adds a createdAt attribute in data if one is not already present. This is obviously not great code since it's looping through every node and has to unserialize the Immutable data object for each node, but it hopefully illustrates what I'm looking to do.
How do I set the data attribute for just the current node?
A few things I've learned:
anchorkey gets you the current key of the selection
Value has a useful shortcut, startKey
Using the currently selected key, you can then loop through the nodes on a document to get the current node.
I'm not sure if Slatejs provides a way to grab a node by key; if so I can't find it, but the above gets me to where I want.

Remove a view from the back history - Ionic2

Anyone knows how to remove a view from the back history (or navigation stack) in ionic2?
In Ionic 1 I solved this with
this.$ionicHistory.nextViewOptions({
disableAnimate: true,
disableBack: true
});
Would be really useful, for example, to fully remove the login page of my application from the history once a successfully login was performed.
Just not showing the back button isn't enough in such case, since Android terminals got their own physical back button on the devices.
I tried, after my login function returned a successful promise and before pushing the next page in the stack:
this.navController.pop();
or
this.navController.remove(this.viewCtrl.index);
but unfortunately both weren't successful :(
obrejacatalin on the https://forum.ionicframework.com/t/solved-disable-back-in-ionic2/57457 found the solution
this.nav.push(TabsPage).then(() => {
const index = this.nav.getActive().index;
this.nav.remove(0, index);
});
so I guess it's important to push the next page first, wait for the promise answer and then remove the current view
To remove one backview you need to use startIndex and count of pages to remove from stack.
this.navCtrl.push(NextPage)
.then(() => {
const startIndex = this.navCtrl.getActive().index - 1;
this.navCtrl.remove(startIndex, 1);
});
See this document for more options like removeView(viewController):
https://ionicframework.com/docs/v2/api/navigation/NavController/#remove
I got the same issue with Ionic 3.
So, only two steps to reset history:
// ...
constructor(public navCtrl: NavController) { }
// ...
this.navCtrl.setRoot(NewPageWithoutPrev);
this.navCtrl.popToRoot();
// ...
Links:
https://ionicframework.com/docs/api/navigation/NavController/#setRoot
https://ionicframework.com/docs/api/navigation/NavController/#popToRoot

Create / Update multiple objects from one API response

all new jsfiddle: http://jsfiddle.net/vJxvc/2/
Currently, i query an api that will return JSON like this. The API cannot be changed for now, which is why I need to work around that.
[
{"timestamp":1406111961, "values":[1236.181, 1157.695, 698.231]},
{"timestamp":1406111970, "values":[1273.455, 1153.577, 693.591]}
]
(could be a lot more lines, of course)
As you can see, each line has a timestamp and then an array of values. My problem is, that i would actually like to transpose that. Looking at the first line alone:
{"timestamp":1406111961, "values":[1236.181, 1157.695, 698.231]}
It contains a few measurements taken at the same time. This would need to become this in my ember project:
{
"sensor_id": 1, // can be derived from the array index
"timestamp": 1406111961,
"value": 1236.181
},
{
"sensor_id": 2,
"timestamp": 1406111961,
"value": 1157.695
},
{
"sensor_id": 3,
"timestamp": 1406111961,
"value": 698.231
}
And those values would have to be pushed into the respective sensor models.
The transformation itself is trivial, but i have no idea where i would put it in ember and how i could alter many ember models at the same time.
you could make your model an array and override the normalize method on your adapter. The normalize method is where you do the transformation, and since your json is an array, an Ember.Array as a model would work.
I am not a ember pro but looking at the manual I would think of something like this:
a = [
{"timestamp":1406111961, "values":[1236.181, 1157.695, 698.231]},
{"timestamp":1406111970, "values":[1273.455, 1153.577, 693.591]}
];
b = [];
a.forEach(function(item) {
item.values.forEach(function(value, sensor_id) {
b.push({
sensor_id: sensor_id,
timestamp: item.timestamp,
value: value
});
});
});
console.log(b);
Example http://jsfiddle.net/kRUV4/
Update
Just saw your jsfiddle... You can geht the store like this: How to get Ember Data's "store" from anywhere in the application so that I can do store.find()?