I'm working on a demo app using Vuejs, and as part of it, I need to get some map data from a local .json file, get certain parts of it (such as lat/long values), and then put it into the appropriate data objects so they can be displayed on a map. After doing a lot of searching it seems that the easiest way it to use jQuery's $.getJSON() method. However, what I can't figure out is how to get the data from within the $.getJSON callback to my Vue markers object.
Here's my relevant code:
<script>
import _ from 'lodash'
import $ from 'jquery'
export default {
name: 'HelloWorld',
data () {
return {
center: {lat: 37.541885, lng: -77.440624},
markers: []
}
},
methods: {
getMarkers: function () {
var apparatus = {}
var address = []
var description = {}
$.getJSON('../static/event1.json', function (data) {
// What do I do here to get outside of this function so
// I can manipulate it?
apparatus = data.apparatus
address = data.address
description = data.description
})
}
},
created () {
this.getMarkers()
}
}
</script>
As you can see by the comment above, I need to get the data from inside the $.getJSON callback, but I can't see what I need to do that. Will this way work, or is there a better way?
I'm not sure where do you want to access this outside the function.
For example, you can assign result of $.getJSON to Vue's instance data by self.data = data, then you can access it outside of your $.getJSON
export default {
name: 'HelloWorld',
data () {
return {
center: {lat: 37.541885, lng: -77.440624},
markers: [],
data: null
}
},
methods: {
getMarkers: function () {
var apparatus = {}
var address = []
var description = {}
var self = this
$.getJSON('../static/event1.json', function (data) {
self.data = data // then you can access data outside of your function by reference this.data
// What do I do here to get outside of this function so
// I can manipulate it?
apparatus = data.apparatus
address = data.address
description = data.description
})
}
},
created () {
this.getMarkers()
}
}
I think you are looking for a way to use your data object's inside your method. You can use this to get access to your data object's :
this.markers = data;
UPDATE :
In your case, you have another scope in your method ( Your callback ) so you ned to use View Model. just before your getJSON line, define it like this :
var vm = this;
Then inside your callback, you can have access to your data object :
vm.markers = data;
notice that if you are using the older version's of vue ( below 2.x ) , you need to use it like this :
this.$data.markers = data;
Related
I am working with the ArcGIS javascript api, which is built on require and the asynchronous module defintion. To create a map, you define all your action inside the callback of the AMD require statement:
require([
"esri/Map",
"esri/views/MapView"
], function(Map, MapView){
const map = new Map({ ... })
const view = new MapView({ ... })
})
I would like to be able to initialize this behavior on command from another module, as well as get access to the map and view objects that are defined within the AMD callback. In order to be able to initialize this on command, I can wrap it in a function, and export that function:
export const makeMap = () => {
require([esri modules], function(Map, MapView){
map = new Map({ ... })
view = new MapView({ ... })
})
}
I can import makeMap into some other module in my code, and call it. This is working nicely. However, I am trying to figure out how I can then access the map and view objects to be able to manipulate them through the UI. First I tried this:
// mapMap.js
export const makeMap = () => {
let mapInstance;
let viewInstance;
require([esri modules], function(Map, MapView){
map = new Map({ ... })
view = new MapView({ ... })
mapInstance = map
viewInstance = view
})
return { mapInstance, viewInstance }
}
// some other module
import { makeMap } from './makeMap'
const { mapInstance, viewInstance } = makeMap()
This obviously does not work - mapInstance and viewInstance are undefined, as the function that defines them inside the AMD callback runs after they are returned from the makeMap() call.
I am not sure how I can get a returned value from the AMD callback. Is this possible? Do I need another paradigm?
One other thing I tried is to pass in a reference-holder object, apply the reference to that object, and then just retrieve them from there when needed. It works, but I feel its not as clean:
// maprefs.js
export const maprefs = {}
// makeMap.js
import { maprefs } from './maprefs'
export const makeMap = (maprefs, mapname) => {
require([esri modules], function(Map, MapView){
map = new Map({ ... })
view = new MapView({ ... })
maprefs[mapname] = { map, view }
})
}
// some module
import { maprefs } from './maprefs'
import { makeMap } from './makeMap'
makeMap(maprefs, "map1")
someButton.addEventListener('click', () => {
// maprefs.map1 is properly defined as { mapInstance, viewInstance } and I can take action on it
maprefs.map1.doSomething
})
I took a look at How do I return the response from an asynchronous call?, which is about retuning values from ajax calls, but I'm struggling to relate that to AMD callbacks.
Is it possible to return the value from the AMD callback to be used elsewhere? I am hoping for a const { map, value } = makeMap() type syntax.
In the scenario that you mention, I think that the best solution is to use esri-loader. Is a tiny library built by ESRI for this purpose exactly, that is, load the ArcGIS JS API library modules at runtime.
ArcGIS Docs - esri-loader
Github ESRI - esri-loader usage
I want to load a JSON file into my mithrilJs app before its startup and want to save this data in some global variable (JSON file is for some run time configuration of mithril application just like app_initializer in Angular)
so far I have done this in my app
import m from 'mithril';
import { a } from './MainView';
var Data = {
fetch: function() {
m.request({
method: "GET",
url: "./client/config/config.json",
})
.then(function(items) {
console.log(items)
// want to store this
m.route(document.body, "/accounts", a)
})
}
}
Data.fetch()
and my Main view file contains
import m from 'mithril';
import {Layout} from "./components/layout";
import {Accounts} from "./components/accounts";
import {AccountNew} from './components/newAccount';
export const a={
"/accounts": {
render: function (vnode) {
return m(Layout, m(Accounts))
}
},
"/accountsNew": {
render: function (vnode) {
return m(Layout, m(AccountNew))
}
},
}
so what could be better approach for this and also I want to store fetched json file data (items) in some global variable like props in react or services in angular , How I can do that to access everywhere in my app
The docs state that you can use onmatch to preload data, here is a rough translation of their example:
var state = {
items: null,
loadItems: function() {
if (state.items === null) {
return m.request("./client/config/config.json").then(function(items) {
state.items = items;
});
}
}
};
const a = {
"/accounts": {
onmatch: state.loadItems,
render: function (vnode) {
return m(Layout, m(Accounts))
}
},
"/accountsNew": {
onmatch: state.loadItems,
render: function (vnode) {
return m(Layout, m(AccountNew))
}
},
}
You can read their two examples in the documentation here: Preloading data.
Alternative solutions
These solutions don't really involve mithril because your are really loading the data before mithril is even used. You should be able to pass your state variable into the component as an attribute, ie. return m(Layout, m(Accounts, {state}));
Dumping JSON String into server side template
If you control the server side as well you can just dump your configuration directly into a global variable by outputting an escaped JSON string assigned to a javascript variable in your base template. I do this to dump model information or session information so my client side code can use it.
<script> var config = ${escapedJSONStringInServerVariable};</script>
Import config directly
You can also just import the configuration directly into your app if you rewrite your config.json to just export your configuration as an object.
import {Config} from ./client/config/config.js
Call m.request directly
Finally you can also just assign the promise returned from m.request to a var and return that promise in loadItems. This should fire m.request immediately but prevent the loading of your templates until the promise is resolved.
var state = (function () {
var configRequest = m.request({
url: "./client/config/config.json"
}).then(function(items) {
state.items = items;
});
return {
items: null,
loadItems: function() {
return configRequest;
}
};
})();
Try to save it in sessionStorage and check it after every reload.
if(!sessionStorage.key('myJson'))
sessionStorage.setItem('myJson','myJson')
So I am creating a Vuejs application and I am trying to fetch firebase data on component mount. That is working, but I try to write the value into a vuejs data property. For this I would only call this.property = snapshot.val(); inside the firebase function (see code below) but that is not working: this is undefined
So my code just is:
export default {
data() {
return {
imageList: "No images!"
}
},
mounted() {
if (!firebase.apps.length) {
// Initialize Firebase
var config = {
...
};
firebase.initializeApp(config);
var database = firebase.database();
var ref = database.ref("images").orderByChild("date");
firebase.database().ref("images/").once('value').then(function(snapshot) {
this.imageList= snapshot.val();
});
}
}
}
I tried calling this.imageList= snapshot.val(); outside of the function with a variable to store the value, and 'this' wasn't undefined anymore, but the data wasn't there because the request hasn't finished yet.
So basically I want to get the snapshot.val(); into this.imageList!
Thanks in advance.
You can use es6 arrow function syntax to solve the issue.
firebase.database().ref("images/").once('value').then((snapshot) => {
this.imageList= snapshot.val();
});
or bind this to the context of the function.
var that = this;
Use an arrow function, a closure, or bind.
firebase.database().ref("images/").once('value').then(snapshot => {
this.imageList= snapshot.val();
});
See How to access the correct this inside a callback.
You can use bind as well.
firebase.database().ref('images/').once('value').then(function(snapshot) {
this.imageList = snapshot.val()
}.bind(this))
I'm new to Ember.js and I'm trying to add an object to the store after an ajax request.
The problem is that it does not reflect on template if I use ember-cli-pagination.
If I use this.store.findAll in model, it works, but when I use this.findPaged it does not.
I'm using ember-inspector and the object appears in the store, just don't in the browser.
My code:
import Ember from 'ember';
import RouteMixin from 'ember-cli-pagination/remote/route-mixin';
export default Ember.Route.extend(RouteMixin, {
actions: {
create: function(email) {
let adapter = Ember.getOwner(this).lookup('adapter:application');
let url = adapter.buildURL('billing/delivery-files');
let store = this.get('store');
let modelName = 'billing/delivery-file';
return adapter.ajax(url, 'POST', {
email: email
}).then(function(data) {
var normalized = store.normalize(modelName, data.object);
store.push(normalized);
});
}
},
model(params) {
return this.findPaged('billing/delivery-file',params); //does not work
// return this.store.findAll('billing/delivery-file'); //works
}
});
Tried the solutions from this issue, and did not work at all.
What am I missing?
Figured out!
After pushing to the store, I needed to push to the paginated array a reference to the store object. Don't know exactly why but it worked like a charm!
model.content.pushObject(pushedRecord._internalModel);
In my case I wanted it at the first position of the array, so I did:
model.content.insertAt(0, pushedRecord._internalModel);
I'm trying to make the following code works without any luck, and I can't see a clear solution on how to do it.
export default {
model: null,
set: function (data) {
this.model = data
},
account: {
update: function (data) {
this.model.account = data
}
}
}
My issue here is that account.update fails because this.model does not exists. I suspect that the sub object gets a new this, hence my issue, but I don't know how to fix it.
I tried the alternative here :
export default (function () {
let model = null
function set (data) {
this.model = data // I also tried without the `this.` but without any luck too
},
function updateAccount(data) {
this.model.account = data
}
return {
'model': model,
'set': set,
'account': {
'update': updateAccount
}
}
})()
But apparently the same rule applies.
Maybe it's worth noting that I'm using Babel to compile ES6 down to ES5 javascript.
It fails because this refers (in this case) to the window object. Reference the object itself like this:
let myModel = {
model: null,
set: function (data) {
myModel.model = data // reference myModel instead of this
},
account: {
update: function (data) {
myModel.model.account = data // reference myModel instead of this
}
}
}
I would take an approach similar to your alternative solution. There is however no need to wrap your code in an IIFE, ES2015 modules are self-contained; you don't need an IIFE for encapsulation.
let model = null,
set = (data) => {
model = data;
},
updateAccount = (data) => {
if (!model) {
throw('model not set');
}
model.account = data;
};
export default {
model,
set,
account: {
update: updateAccount
}
};
Since you are already using Babel, I also used arrow functions and the new shorthand properties to make the code a little shorter/readable.