Vuejs Transition not functioning with computed property - vue.js

I am creating a simple inventory system that will have various categories for the items, as well as the option to display all items.
Going from the 'all' category to the 'general' category will remove the unnecessary item, but leaves a gap for a significant period of time and there is not animation of the item after the gap sliding into place.
I am doing this using Vuejs and vue2-animate.
computed:
{
active_items: function()
{
var _self = this;
if(_self.active_category === 'all')
{
return _self.items;
} else
{
return _self.items.filter(function(i)
{
return i.category === _self.active_category;
});
}
}
},
https://jsfiddle.net/Crotanite/cn07tmho/8/

The gap that is left in place of disappearing list items is because an element that transition is being applied to, stays in place until leave-active animation phase is finished.
Simple fix, is to add position: absolute; to a leaving element. This will allow sibling list items to take it's position.
Below is updated version of your example with additional class zoomOut__absolute added to leave-active-class attribute. Additional class is added to avoid overwriting styles of animate.css:
JSFiddle

Related

Vue Draggable with touch - drop doesn't trigger

I have been working on a website that has to function on both desktop and tablets. Part of the website is having three columns and being able to drag orders from column to column. Sometimes on drop, the user has to answer a few questions or change some of the data of that specific order. This happens in a pop-up window that is triggered by an #drop function (for example #drop="approved()". The method approved() then checks the status of the dropped order and shows the pop-up window).
When I am on desktop, everything works just fine. But when I switch to iPad Pro in the developer tools, nothing happens. I implemented Vue Draggable, which says to work with touch devices. In their examples I can't find anything about touch events or adding new handles for touch, so I don't know what to do now.
The dragging works just fine with touch devices, it's just the #drop function that doesn't trigger.
The dropzone (it includes a component that contains the draggables and a lot of if-statements):
<div class="col-md-4 border" #dragover.prevent #drop="approved()">
<Wachtrij class="fullHeight" :data2="opdrachtenData2"></Wachtrij>
</div>
The method:
export default {
methods: {
...
approved() {
console.log("Function approved() is being executed.")
if (this.draggingOrder.status === 5) {
this.popupGekeurd = true;
}
else if (this.draggingOrder.status === 6) {
this.popupTochGoed = true;
}
else if ([40, 52, 42,41,49,55,54].indexOf(this.draggingOrder.status) !== -1) {
this.back = true;
}
},
...
}
}
The problem seems to be that you are using native events, while the touch implementation does not (always?) use these events. It is intended that you use a draggable component with one of the events outlined in the documentation. In your case the start and end events look promising. This event has a few properties (docs), some of them being to and from.
Let's assume that we have the following code:
<draggable v-for="(zone, index) in zones" v-model="zones[index]" :class="['dropzone', `zone-${index}`]" :key="`dropzone-${index}`" :options="options" #start="start" #end="end">
<div v-for="item in zones[index]" class="dropitem" :key="`dropitem-${item.id}`">
{{ item.title }}
</div>
</draggable>
This creates a few zones, each filled with their own items. Each array item of zones is changed based on where you move each item. You can then use start to have information on when you start moving an item, and end to have information on when you stop moving an item, and where that item came from and where it ended up. The following methods show off what you can do with that in this case:
methods: {
start (event) {
console.log('start', event);
},
end (event) {
console.log('end', event);
const { from, to } = event;
if (to.className.match(/\bzone-2\b/)) {
console.log('Zone 2 has something added!')
}
if (from.className.match(/\bzone-0\b/)) {
console.log('Zone 0 had something removed!');
}
}
}
We make our dropzones with a class zone-0, zone-1 or zone-2 in this case, so we can use the class name to determine which dropzone we ended up in.
An alternative way to determine which zone was changed is to simply use a watcher. Since zones changes based on where you move items, you can simply watch a particular dropzone for changes and do things based on that.
watch: {
'zones.1': {
handler (oldZone, newZone) {
if (Array.isArray(oldZone) && Array.isArray(newZone) && oldZone.length !== newZone.length) {
console.log('Zone 1 was changed from', oldZone, 'to', newZone);
}
}
}
}
A full example can be found on codesandbox.

element not updated when data changes

I have a vaadin-checkbox:
<vaadin-checkbox id=[[item.id]] disabled="true" checked="[[item.checked]]">[[item.description]]</vaadin-checkbox>
I defined my properties:
static get properties() {
return {
items: {
type: Array,
notify: true,
value: function() {
return [];
}
}
};
}
When I now change the data by pressing some button:
_selectItem(event) {
const item = event.model.item;
if (item.checked === true) {
this.$.grid.deselectItem(item);
} else {
this.$.grid.selectItem(item);
}
item.checked = !item.checked;
}
The state of the checkbox is still checked="true". Why isnt the checkbox getting updated? The same thing when I change the description of the item:
_selectItem(event) {
event.model.item.description = 'test';
}
The test description is never appearing. The checkbox is never getting updated.
The reason why the checkbox does not get updated by the button click handler is in the Polymer 2 data system. Polymer does not detect the change and does not update the template accordingly.
In order to make the change in a way that Polymer would detect it you have two options:
Use this.set(`items.${event.model.index}.checked`, !item.checked) if you can reliably assume that the index used by dom-repeat always matches that elements's index in the items array (it is not the case if you use sorting or filtering features of dom-repeat). See an example here https://jsfiddle.net/vlukashov/epd0dn2j/
If you do not know the index of the updated item in the items array, you can also use the Polymer.MutableData mixin and notify Polymer that something has changed inside the items array without specifying the index of the changed item. This is done by calling this.notifyPath('items') after making a change. However, this requires that your element extends the Polymer.MutableData mixin, and that dom-repeat has the mutable-data attribute set. See an example here: https://jsfiddle.net/vlukashov/epd0dn2j/24/
More information on this in the Polymer 2 docs.

vue-router view caching / not resetting data

Im working on a car sales website and using vue-router.
I have an index page with a list of all cars for sale, and then when clicked they link to the single view of that specific vehicle.
I have a large 'header' image on the single view page and have it inside a container with a fixed height so that when the page loads there is not jumping in page height.
When going to this single view, I do an API call to get the vehicle data and then wish to fade in the heading image.
To do this:
<div class="singleVehicle__mainImage">
<span :style="styles" :class="{'imageLoaded' : mainImageLoaded }" v-if="vehicle"></span>
</div>
export default {
data() {
return {
vehicle: null,
styles: {
backgroundImage: null
},
mainImageLoaded: null
}
},
created() {
this.getVehicle().then(() => {
this.mainImageBackground();
});
},
methods: {
mainImageBackground() {
var source = "IMAGE SOURCE URL";
this.styles.backgroundImage = "url("+source+")";
var $this = this;
var img = new Image();
img.onload = function() {
$this.mainImageLoaded = true;
}
img.src = source;
if (img.complete) img.onload();
}
}
}
By default, the span inside the image wrapper has a 0 opacity and then that is transitioned to 1 when the .imageLoaded class is added.
This works fine, but only the first time each vehicle loaded. The image waits till it loads and then fades in. Everyother time afterwards the image simply pops in when it loads almost like the imageLoaded class is not being reset / the data is not being reset when leaving the view.
When clearing browser cache, it works again but once for each vehicle view.
This is probably due to your v-if="vehicle". The vehicle call is possibly taking longer and so the span is not showing until after the class is added or some timing issue related to that.

Durandal: Multiple Routes, One ViewModel/View

I have 3 routes: items/one, items/two, and items/three and they're all pointing to 'items' vm/view.
in the items.js activate function, I'm checking the url, and based on that, I'm changing a filter:
function activate(r) {
switch (r.routeInfo.url) {
case 'items/one': vm.filterType(1); break;
case 'items/two': vm.filterType(2); break;
case 'items/three': vm.filterType(3); break;
}
return init(); //returns a promise
}
The items view has a menu with buttons for one, two, and three.
Each button is linked to an action like this:
function clickOne() {
router.navigateTo('#/items/one');
}
function clickTwo() {
router.navigateTo('#/items/two');
}
function clickThree() {
router.navigateTo('#/items/three');
}
this all works and I get the right filter on the view. However, I've noticed that if I'm on 'one', and then go to 'two', the ko-bound variables update in 'real-time', that is, as they're changing, and before the activate promise resolves, which causes the transition to happen twice (as the data is being grabbed, and after the activate function returns).
This only happens in this scenario, where the view and viewmodel are the same as the previous one. I'm aware that this is a special case, and the router is probably handling the loading of the new route with areSameItem = true. I could split the VMs/Views into three and try to inherit from a base model, but I was hoping for a simpler solution.
I was able to solve the issue by simply removing the ko bindings before navigation using ko.cleanNode() on the items containing div.
Assuming that in your parent view you've a reference to router.activeItem with a transition e.g.
<!--ko compose: {model: router.activeItem,
afterCompose: router.afterCompose,
transition: 'entrance'} -->
<!--/ko-->
then the entrance transition happens on every route you've setup to filter the current view.
But this transition should probably only happen on first time visit and from that point on only the view should be updated with the filtered data. One way to accomplish that would be to setup an observable filterType and use filterType.subscribe to call router.navigateTowith the skip parameter.
Something along the line:
var filterType = ko.observable();
filterType.subscribe(function (val) {
// Create an entry in the history but don't activate the new route to prevent transition
// router plugin expects this without leading '/' dash.
router.navigateTo(location.pathname.substring(1) + '#items/' + filterType(), 'skip');
activate();
});
Please note that the router plugin expects skipRouteUrl without leading / slash to compare the context.path. https://github.com/BlueSpire/Durandal/blob/master/App/durandal/plugins/router.js#L402
Your experience might be different.
Last in order to support deep linking in activate:
function activate(routerdata) {
// deep linking
if (routerdata && routerdata.filterType && (routerdata.filterType !== filterType() ) ) {
filterType(routerdata.filterType);
}
return promise;
};

extjs 4.1 how to reset the itemselector

I am using extjs 4.1.1a for developing some application.
I had a form consisting of two combo-boxes and an item-selector.
Based on the value selected in first combo-box , the itemselector will load its data from database. This is working fine.
My problem is, if i reselect the first combo-box the new data will be displayed in itemselector along with previous data displayed in itemseletor .That is previous data displayed in itemselector will remain there itself.
for example: name "test1" consists of ids 801,2088,5000. on selecting test1 in firstcombobox itemselector must show output as below.
and if "test2" consists of ids 6090,5040. on selecting test2 in firstcombobox itemselector must show output as below.
problem is. for first time if i select "test1" from firstcombobox , output will come as expected. if i reselect "test2" from firstcombobox , output will come as below.
as you can see, previous data displayed (marked in red rectagle) remains there itself with new data displayed (marked with green rectangle).
I want for every reselection of first combobox, previously displayed data in itemselector to be erased before printing new data on itemselector.
How can I reset the itemselector for every reselection of first combobox?
You should remove all items from the store of the itemselector by the removeAll command. After that you should load the store of the itemselector.
itemselector.store.removeAll();
itemselector.store.load();
Any solutions above solve my problem.
i found solution from Sencha Forum.
https://www.sencha.com/forum/showthread.php?142276-closed-Ext-JS-4.0.2a-itemselector-not-reloading-the-store
in the itemselector.js file, change the line marked below.
populateFromStore: function(store) {
var fromStore = this.fromField.store;
// Flag set when the fromStore has been loaded
this.fromStorePopulated = true;
// THIS LINE BELOW MUST BE CHANGED!!!!!!!!!!!!
fromStore.loadData(store.getRange()); //fromStore.add(store.getRange());
// setValue waits for the from Store to be loaded
fromStore.fireEvent('load', fromStore);
},
You need to insert...
this.reset();
at the head of the function that is inserting the data.
As an example...
Ext.override( Ext.ux.ItemSelector, {
setValue: function(val) {
this.reset();
if (!val) return;
val = val instanceof Array ? val : val.split(this.delimiter);
var rec, i, id;
for (i = 0; i < val.length; i++) {
var vf = this.fromMultiselect.valueField;
id = val[i];
idx = this.toMultiselect.view.store.findBy(function(record){
return record.data[vf] == id;
});
if (idx != -1) continue;
idx = this.fromMultiselect.view.store.findBy(function(record){
return record.data[vf] == id;
});
rec = this.fromMultiselect.view.store.getAt(idx);
if (rec) {
this.toMultiselect.view.store.add(rec);
this.fromMultiselect.view.store.remove(rec);
}
}
}
});
are u got it?
when u select that combobox frist stoe of item selector is null after store load with ur pass the para meters
for example
store.load(null),
store.proxey.url='jso.php?id='+combobox.getrawvalue(),
store.load();
like that so when ur select a value in ur combobox that time ur used a listeners to ur combobox in that listners ur used above code , select ur some value in combobox that time frist store is get null after ur pass some values to json.php then store load with responce so that time old data is remove and new data load in that store
if u post ur code i will give correct code
I ran into the same issue with ExtJS 4.2.1. I got it to work by calling reload() on the data store and then setValue() with an empty string on the item selector in the data store's reload() callback.
Ext.create("Ext.form.field.ComboBox", {
// Other properties removed for brevity
listeners: {
change: function(field, newValue, oldValue, eOpts) {
Ext.getStore("ExampleStore").reload({
callback: function() {
Ext.getCmp("ExampleItemSelector").setValue("");
}
});
}
}
});
Ext.create("Ext.data.Store", {
storeId: "ExampleStore",
// Other properties removed for brevity
});
Ext.create("Ext.form.FormPanel", {
// Other properties removed for brevity
items:[{
xtype: "itemselector",
id: "ExampleItemSelector",
// Other properties removed for brevity
}]
});
For any folks that are curious, I'm fairly convinced there's a bug in the item selector's populateFromStore() function. When the function is called, it blindly adds all of the values from the bound store (store) to the internal store (fromStore). I suspect there should be a call to fromStore.removeAll() prior to the call to fromStore.add(). Here's the relevant code from ItemSelector.js.
populateFromStore: function(store) {
var fromStore = this.fromField.store;
// Flag set when the fromStore has been loaded
this.fromStorePopulated = true;
fromStore.add(store.getRange());
// setValue waits for the from Store to be loaded
fromStore.fireEvent('load', fromStore);
},
EDIT 12/18/2013
If you've configured any callback events on the item selector (e.g. change), you may want to disable the events temporarily when you call setValue(""). For example:
var selector = Ext.getCmp("ExampleItemSelector");
selector.suspendEvents();
selector.setValue("");
selector.resumeEvents();
I had the same problem and finally I decided to modify the extjs source code, not considering it a big issue as extjs itself its saying in the start of the file
Note that this control will most likely remain as an example, and not as a core Ext form
control. However, the API will be changing in a future release and so should not yet be
treated as a final, stable API at this time.
Based on that, as jstricker guessed (and sadly I didn't read and took me a while to arrive to the same conclusion), adding fromStore.removeAll() before fromStore.add() solves the problem.
Outside of the problem (but I think it can be interesting as well), additionally, I also added listConfig: me.listConfig in the MultiSelect configuration (inside createList), that way it's possible to format each item additional options (such as images, etc.) setting in the 'itemselector' the option listConfig as it's explained in the (irrealistic) documentation.
Need to reset the store used in ItemSelector that can be done by setting Empty object like below. Also need to call clearValue() method of ItemSelector component.
store.setData({});
ItemSelectorComponent.clearValue();