I'm trying to show loading state in v-simple-data, but for some reason, it doesn't work, maybe there is another way to do it?
Here is my code:
https://codesandbox.io/s/vuetify-template-forked-bmobx?file=/src/App.vue
You are resetting the dataLoading variable outside of the timeout. Therefore it is immediately set to false. You should move it inside the timeout callback.
initialize() {
//you do not need to call the set method; since you are setting a primitive data type; reactivity is detected
//this.$set(this, "dataLoading", true);
this.dataLoading = true
let vm = this;
setTimeout(() => {
vm.items = [
{ name: "Art", position: "Manager" },
{ name: "David", position: "Salesman" },
];
// reset the dataLoading only after the data has been loaded.
vm.dataLoading = false
}, 1000);
// this line of code does not wait for the setTimeout to finish. This line of code was resetting your variable without waiting for the timeout to complete; thus you never saw the data loading indicator
//this.$set(this, "dataLoading", false);
}
Related
i have this deep getter:
getTotalVideoLength: {
cache: false,
get() {
let duration = 0;
_.forEach(this.videos, (video) => {
duration = duration + video.duration;
});
console.log(duration);
return duration;
}
},
In the begin it logs undefined but after a few milliseconds it logs a number, but when i pass that 'getTotalVideoLength' as a prop to a child component it is always NaN.
Any help is welcome!
I'm thinking you may need to change your approach a bit. I'm sure you can make your code work with a computed property, but why force it with a hacky approach? Is there any reason why you need to use a computed value for this? What if you tried it with a data-property and method and called the method onMount to set the data-property so that you can guarantee that the values are already prepared before it's set? Try this code out and let me know how it works, please.
data() {
totalVideoLength: 0,
},
methods: {
setTotalVideoLength(videos) {
this.totalVideoLength = videos.reduce((accumulator, { duration }) => accumulator + duration, 0);
},
},
onMount() {
this.setTotalVideoLength(this.videos);
}
I have this vue component:
export default {
data: function() {
return {
editor: new Editor({
//some options
}),
}
},
computed: {
doc(){ // <--------------------- take attention on this computed property
return this.editor ? this.editor.view.state.doc : null;
},
},
watch: {
doc: {
handler: function(val, OldVal){
// call some this.editor methods
},
deep: true,
immediate: true,
},
},
}
Will computed property doc be dependent on a data property editor if I use this.editor only for checking if it is defined and not use it for assigning it to the doc? I mean, If I will change this.editor will doc be changed? Also, I have watcher on doc so I need to know if I will cause an infinite loop.
In the doc property computation, you use:
the editor property (at the beginning of your ternary, this.editor ? ...)
if editor exists, the editor.view.state.doc property
So the computation of doc will be registered by Vue reactivity system as an effect related to the properties editor and (provided that editor exists) to editor.view.state.doc. In other words, the doc property will be reevaluated each time one of these two properties changes.
=> to reply to the initial question, doc will indeed depend on editor.
This can be toned though, because by 'property change', we mean:
for properties of primitive types, being reassigned with a different value
for objects, having a new reference
So, in our case, if editor, which is an object, is just mutated, and that this mutation does not concern it's property editor.view.state.doc, then doc will not be reevaluated. Here are few examples:
this.editor = { ... } // doc will be reevaluated
this.editor.name = ' ... ' // doc will NOT be reevaluated
this.editor.view.state.doc = { ... } // doc will be reevaluated
If you want to understand this under the hood, I would recommand these resources (for Vue 3):
the reactivity course on Vue Mastery (free)
this great talk and demo (building a simple Vue-like reactivity system)
About the inifinite loop, the doc watcher handler will be executed only:
if doc is reassigned with a different value
in the case where docis an object, if doc is mutated (since you applied the deep option to the doc watcher)
The only possibility to trigger an infinite loop would be to, in the doc watcher handler, mutate or give a new value to doc (or editor.view.state.doc). For example (cf #Darius answer):
watch: {
doc: {
handler: function(val, OldVal){
// we give a new ref each time this handler is executed
// so this will trigger an infinite loop
this.editor.view.state.doc = {}
},
// ...
},
}
=> to reply to the second question, apart from these edge cases, your code won't trigger a loop. For example:
watch: {
doc: {
handler: function(val, OldVal){
// even if we mutate the editor object, this will NOT trigger a loop
this.editor.docsList = []
},
// ...
},
}
Changing editor variable should work, but changing Editor content may not, as it depends on Editor class and how it respects reactivity.
For example:
export default {
data: function() {
return {
editor: {text: '' }
}
}
}
...
this.editor.text = 'Text' // works
this.editor.text = {param: ''} // works
this.editor.text.param = 'value' // works
this.editor.param = {} // does't work, as creation of new property is not observable
If editor observer works and you are changing editor property in observer, which 'reinitializes' internal structures, it may lead to infinite loop:
var Editor = function() {
this.document = {}
this.change = () => { this.document = {} }
}
var data = new Vue({
data: () => ({
editor: new Editor(),
check: 0
}),
watch: {
editor: {
handler() {
this.check++
console.log('Changed')
if (this.check < 5)
this.editor.change()
else
console.log('Infinite loop!')
},
deep: true,
immediate: true
}
}
})
data.editor.change()
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
In such case, extra checking is necessary before making the change.
Please help me out, how to handle this error i cant seem to handle this out as i am new to vue.
what im doing is getting data from server in store vuex with action. Now in component im accessing that data with getter in computed property and trying to watch that property but on component mount i get that error in console but functionality works fine.
data: function() {
return {
settings_flags :{
general: 0,
privacy: 0,
layouts: 0,
message: 0
}
}
}
1: mounting
mounted() {
let self = this;
self.userid = this.getUserId();
this.$store.dispatch('getGallerySettings',self.req);
self.initial_settings();
}
2: computed
computed: {
get_settings() {
return this.$store.getters.getGallerySettings;
}
}
3: watch
watch: {
'get_settings': {
deep: true,
handler() {
let self =this;
if (this.$_.isMatch(self.get_settings.gallery_settings.general,self.initialSettings.gallery_settings.general) == false) {
self.settings_flags.general = 1;
} else {
self.settings_flags.general = 0;
}
}
}
}
It seems to me that your watcher is looking for a property 'general' that is a child of gallery_settings.
get_settings.gallery_settings.general
In the meantime in data you have a property general that is a child of 'settings_flags'. Those two don't line up. So make sure that either your watcher is looking for something that exists when the component starts up, or tell your watcher to only start watching ' get_settings.gallery_settings.general' when 'get_settings.gallery_settings' actually exists.
if (get_settings.gallery_settings) { do something } #pseudocode
I'm not sure that's your problem, but it might be.
Some of my acceptance-tests (which involve actions) fail randomly when run with all other tests but never fail when I run them in isolation.
The Error: Assertion Failed: calling set on destroyed object is triggered in my action
I don't get any issue while using the table as a user so these issues only appear in tests. So I'm not sure if it's just because the app isn't destroyed correctly after each run.
Can I somehow see why the object is about to be destroyed or which observers are blocking it?
foos/index/route.js
startFoo(foos) {
foos.forEach(function(foo) {
foo.set('status', 'active');
foo.save();
});
},
This action gets passed down to a component (table) which shows a list of foo-models. Each row can be selected, doing so add the foo model of this row to a property selectedRows on this table component.
components/my-table/table.js
visibleColumns: Ember.A(),
selectedRows: Ember.A(),
selectRow(row) {
let selectedRows = this.get('selectedRows');
if (selectedRows.contains(row)) {
selectedRows.removeObject(row);
} else {
selectedRows.addObject(row);
}
},
isSelected(row) {
return this.get('selectedRows').contains(row);
},
components/my-table/header/template.hbs
action.cb is the function startFoo
<button {{action action.cb table.selectedRows}}>
{{im-icon icon=action.icon}}
</button>
The table component is pretty modular so it has header, columns, cells, rows and to share the state (like selected rows) I use an Ember.Object which is passed to all parts of the table component (which might be the issue?!!?)
components/my-table/row/component.js
isSelected: computed('table.selectedRows.[]', {
get(/*key*/) {
return this.get('table').isSelected(this.get('content'));
},
set(/*key, value*/) {
this.get('table').selectRow(this.get('content'));
return this.get('table').isSelected(this.get('content'));
},
}),
components/my-table/row/template.hbs
content is a foo model
<td class="shrink">{{input type='checkbox' checked=isSelected}}</td>
{{#each table.visibleColumns as |column|}}
{{my-table/cell content=content column=column}}
{{/each}}
Test
setup and teardown is ember-cli default
moduleForAcceptance('Acceptance | Foos');
test('click on action start changes state to active', function(assert) {
server.create('foo', {
status: 'paused'
});
// This is an ember-page-object
fooPage
.visit()
.selectFoo()
.clickStart();
andThen(function() {
assert.equal(fooPage.foos(1).status(), 'active', 'runs action');
});
});
Checking isDestroyed prior to setting should do the trick
isSelected: computed('table.selectedRows.[]', {
get(/*key*/) {
return this.get('table').isSelected(this.get('content'));
},
set(/*key, value*/) {
if (this.get('isDestroyed')) {
return;
}
this.get('table').selectRow(this.get('content'));
return this.get('table').isSelected(this.get('content'));
},
}),
is it possible to remove a Listener from an Ext.Panel after the call?
I have a tap-Listener, which I want to remove after calling the first time. I tried many ways to remove the Listener but it's still calling:
registerListeners: function()
{
// this = Ext.Controller
// this.view = Ext.Panel
this.view.on('tap', this.onTap, this, {element: 'body'});
},
unregisterListeners: function(evt, el, o)
{
console.log("Removing Event...");
this.view.el.un('tap', this.onTap, this); // Don't work, on the next tap its still calling
},
onTap: function(evt, el, o)
{
Ext.ControllerManager.get('mycontroller').unregisterListeners();
}
I'm really confused?!? :( Any suggestions?
Yes, you can set the single option in the on/addListener call.
myButton.on('click', function(){
/* do stuff */
}, this, { single : true });
// In your case:
this.view.on('tap', this.onTap, this, {element: 'body', single: true});
Check the docs for addListener on http://dev.sencha.com/deploy/touch/docs/?class=Ext.Component