So, I have an object inside a ReactiveDict that I want to update:
dataSet = new ReactiveDict('dataSet');
dataSet.set({
defaultInfo: {
title: 'Default'
}
});
updateTitle(title) {
// not sure what to put here to update the default title
dataSet.set({ })
}
Thoughts? I'm using ES6.
So, I was able to create a solution, though not exactly what I had in mind.
I wasn't able to find a way to update the object, only replace it with a new object:
updateTitle(title) {dataSet.set({
defaultInfo: _.extend(dataSet.get('defaultInfo'), {title: title})
})}
This is using underscoreJS for the _.extend
Related
i am doing an app in Vuejs and i am stuck with a problem in replacing one object for another that comes from an API every 10 seconds. I have this at the moment:
watch: {
myObj() {
for (let [key, tuner] of Object.entries(myObj)) {
---- some code ----
}
}
},
},
created() {
setInterval(this.callMyApi(), 10000);
},
I am watching the object and then use it in a for loop that does some logic. I saw the documentation mention using 'this.$set()' but this only adds a property to the object and i want replace one for another. Thanks for the help.
I would use:
this.myObj = JSON.parse(JSON.stringify(newObj))
to make a deep copy of the object inside this.callMyApi().
To watch for changes on this object do the following: create a new bool variable and use it on the component you want to update:
<componenttoupdate :reactto=objupdated/>
data: {
...
objupdated: false
...
}
and switch the objupdated bool state anytime you do the deep copy on your function, and so the component will update.
This is a cheaper solution than keeping watchers over large objects that may get updated very often as yours.
I'm migrating an old script which I didn't write from version 0.11 to 2.5.4 and I'm getting a warning saying :
Replace this.$eval('reportData | reportFilter false') with a solution using normal JavaScript
Line 327: assets/js/custom-reports.js
Reason: vm.$eval has been removed, as it has no real use
More info: http://vuejs.org/guide/migration.html#vm-eval
I can see in the code its setting these values:
this.$set('reportData[' + key + '].selected', !selectAll);
And using them here:
var data = this.$eval('reportData | reportFilter false');
Has anyone got any idea whats going on here and how I can rewrite this to work in a new way?
That looks like it is filtering reportData with a filter called reportFilter which I'm guessing is being passed false as a parameter. Filters in Vue 2 don't work the same way, so you will need to move reportFilter to a method, however, if this is being used across multiple components you will probably want to create a mixin, so:
// Filters mixin
const Filters = {
methods:{
reportFilter(data, flag){
// reportFilter method
}
}
}
Then in any components where reportFilter is being used you will want to use the mixin:
new Vue({
// ...
mixins: [Filters],
// ...
})
You can then change your $eval code to:
var data = this.reportFilter(reportData, false);
Here's a JSFiddle to give you an idea of how that works: https://jsfiddle.net/4b8vqccs/
I have an actual quite simple situation:
A route to add a new item. In the corresponding controller I pre define a mockup model of my new item:
item: Ember.Object.create({
date: moment(),
amountTotal: '',
netto: '',
//...more properties
}),
This needs to be an Ember-Object, not a plain js-Object, because otherwise other things would break.
When I try to safe that newly created item:
actions: {
addItem: function() {
let expense = this.store.createRecord('expense', this.get('item'));
},
//....
}
I get the error
Assertion Failed: Cannot clone an Ember.Object that does not implement Ember.Copyable
So my Question is:
How can I create an Object that implements Ember.Copyable?
Or is there any way around this?
Yes, I've read the two other questions about that.
The first gives a soulution where I would initially create a record in the store. This has the usual downsides to it (already populating in lists, ..).
I've also tried all ways I could think of to get around that like
item: Ember.Copyable.create({...})
// or
let newItem = Ember.copy(this.get('item'));
let expense = this.store.createRecord('expense', newItem);
// and many more
Finally:
If there is a way to mock up a new Item (best with the definitions of the model) without creating a record, this would be the absolute best...
You can try specifying default value for all the model properties, and then simply you don't need to provide argument for createRecord method.
Like the below, models/expense.js and you can simply say this.store.createRecord('expense') this will come up with all the default values.
export default Model.extend({
name: attr('string',{ defaultValue: 'Sample Name'}),
date: attr('date',{
defaultValue(){
//You can write some code and the return the result.
//if you have included moment, you can use that.
return Date();
}
}),
amount: attr('number',{ defaultValue: 10}),
totalAmount: Ember.computed('amount',function(){
return this.get('amount')*10;
})
});
Using JSON.stringify and JSON.parse like the below,
this.store.createRecord('expense', JSON.parse(JSON.stringify(this.get('item'))))
Created twiddle for reference.
Im relatively new with VueJS, and I've got no clue about how to make some data globally available. I would like to save data like API endpoints, user data and some other data that is retrieved from the API somewhere where each component can get to this data.
I know I can just save this with just vanilla Javascript but I suppose there is a way to do this with VueJS. I may be able to use the event bus system to get the data but I don't know how I can implement this system to my needs.
I would appreciate it if somebody can help me with this.
Make a global data object
const shared = {
api: "http://localhost/myApi",
mySharedMethod(){
//do shared stuff
}
}
If you need to expose it on your Vue, you can.
new Vue({
data:{
shared
}
})
If you don't, you can still access it inside your Vues or components if you've imported it or they are defined on the same page.
It's really as simple as that. You can pass shared as a property if you need to, or access it globally.
When you're just starting out there is no real need to get complicated. Vuex is often recommended, but is also often overkill for small projects. If, later, you find you need it, it's not that hard to add it in. It's also really for state management and it sounds like you just really want access to some global data.
If you want to get fancy, make it a plugin.
const shared = {
message: "my global message"
}
shared.install = function(){
Object.defineProperty(Vue.prototype, '$myGlobalStuff', {
get () { return shared }
})
}
Vue.use(shared);
Vue.component("my-fancy-component",{
template: "<div>My Fancy Stuff: {{$myGlobalStuff.message}}</div>"
})
new Vue({
el: "#app"
})
Now, every Vue you create and every component has access to it. Here is an example.
You can use Store which will hold your application state.
const store = new Vuex.Store({
state: {
userData: []
},
mutations: {
setUserData (state, data) {
state.userData = data
}
}
})
With this you can access the state object as store.state, and trigger a state change with the store.commit method:
store.commit('setUserData', userData)
console.log(store.state.userData)
Vue Mixin
// This is a global mixin, it is applied to every vue instance.
// Mixins must be instantiated *before* your call to new Vue(...)
Vue.mixin({
data: function() {
return {
get $asset() {
return "Can't change me!";
}
}
}
})
template
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="app">
In Root: {{globalReadOnlyProperty}}
<child></child>
</div>
Or
Vue.prototype.$asset = 'My App'
I just use an environment.js file to store all of my endpoints as object properties.
var urls = {};
urls.getStudent = "api/getStudent/{id}";
etc...
Then I put reference to this environment.js file in the head of document on pages where I have VueJS code that needs access to those endpoints. Im sure there are many ways to do this.
I'm using ember.js RC1 + ember-data rev 11 (but I also need some plain ajax for configuration like models). I want to loop over a simple objects list and display the records (note -here I create just a basic array)
The content I have bound has the following custom find method defined
App.Foo = DS.Model.extend({
name: DS.attr('string')
}).reopenClass({
records: [],
all: function() {
return this.records;
},
find: function() {
var self = this;
$.getJSON('/api/foo/', function(response) {
response.forEach(function(data) {
//say I want to kill everything in the array here for some strange reason...
self.records = [];
//the template still shows the record ... not an empty list ?
}, this);
});
return this.records;
}
});
My other model uses this directly
App.Related = DS.Model.extend({
listings: function() {
return App.Foo.find();
}.property()
});
Now inside my template
{{#each foo in related.listings}}
{{foo.name}}<br />
{{/each}}
The list loads up with whatever I put in the array by default (say I add a simple object using createRecord like so)
add: function(record) {
this.records.addObject(App.Foo.createRecord(record));
},
and when the template is rendered I see anything listed here... but as I put in the comments above, if I decide to remove records or null out the list that is bound it doesn't seem to reflect this in any way.
Is it possible to bind a simple array as I have and yet remove items from it using something basic such as splice? or even a drastic self.records = []; ?
self.records.splice(i, 1);
Even when I query the client manually after the splice or empty work it returns 0
console.log(App.Foo.all().get('length'));
Initially I see records, but then I see they are gone (yet the html doesn't change)
I understood your question this way, that the following remark is the point your are struggling with:
response.forEach(function(data) {
//say I want to kill everything in the array here for some strange reason...
self.records = [];
//the template still shows the record ... not an empty list ?
}, this);
You are wondering, why your template is showing no empty list? It's because you did not tell Ember when to update the template. You can tell Ember this way:
App.Related = DS.Model.extend({
listings: function() {
return App.Foo.find();
}.property("App.Foo.records.#each")
});
Now Ember knows, whenever something is added or removed from your array, it should update the listings property of your model. And therefore it knows that your view needs rerendering.
One additional remark to the orignal question regarding "simple javascript arrays". When you use Ember, you actually do not instantiate simple js arrays. When you declare:
var a = []; // is the same as -> var a = Ember.A();
Ember does some magic and wraps in an enhanced ember version of an array (Ember.NativeArray), which enables you to use such property dependency declarations mentioned above. This enables Ember to use ArrayObservers on those arrays, although they may feel like a plain JS Array.
You need to use the set method when you modify properties and get when you return them, or else Ember won't be able to do its magic and update the template.
In your case, there is an additional problem, which is that in find(), you return a reference to records before your asynchronous getJSON call replaces it with a new empty array. The calling method will never see the new array of records. You probably want to use clear() instead.
Your model should look something like this:
App.Foo = DS.Model.extend({
name: DS.attr('string')
}).reopenClass({
records: [],
all: function() {
// can't use 'this.get(...)' within a class method
return Ember.get(this, 'records');
},
findAll: function() {
var records = Ember.get(this, 'records');
$.getJSON('/api/foo/', function(response) {
records.clear();
// in this case my json has a 'foos' root
response.foos.forEach(function(json) {
this.add(json);
}, this);
}, this);
// this gets updated asynchronously
return records;
},
add: function(json) {
// in order to access the store within a
// class method, I cached it at App.store
var store = App.get('store');
store.load(App.Foo, json);
var records = Ember.get(this, 'records');
records.addObject(App.Foo.find(json.id));
}
});
Note that the addObject() method respects observers, so the template updates as expected. removeObject() is the corresponding binding-aware method to remove an element.
Here's a working jsfiddle.