Nuxt vuex - moving store from Vue - axios

I have been fiddling with moving a tutorial I did in Vue to Nuxt. I have been able to get everything working, however I feel I'm not doing it the "proper way". I have added the Nuxt axios module, but wasnt able to get it working, so I ended up just using the usual axios npm module. Here is my store:
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(Vuex)
Vue.use(VueAxios, axios)
export const state = () => ({
events: []
})
export const mutations = {
setEvents: (state, events) => {
state.events = events
}
}
export const actions = {
loadEvents: async context => {
let uri = 'http://localhost:4000/events';
const response = await axios.get(uri)
context.commit('setEvents', response.data)
}
}
I would like to know how to re-write this store using the #nuxtjs/axios module. I also didnt think I'd need to import vuex here, but if I dont, my app doesn't work.
Thanks for any help!

Using the #nuxtjs/axios module, you can configure axios inside your nuxt.config.js:
// nuxt.config.js
export default {
modules: [
'#nuxtjs/axios',
],
axios: {
// proxy: true
}
}
You can use it inside your store (or components) with this.$axios
// In store
{
actions: {
async getIP ({ commit }) {
const ip = await this.$axios.$get('http://icanhazip.com')
commit('SET_IP', ip)
}
}
}

Related

Nuxt.js - Implementing a component using Plugin

I would like to implement a custom Toaster component into my NuxtJs application by this method this.$toast.show({}) What is the best way of approaching this? Sadly I can't find any documentation on this.
Sorry, I arrive one year late...
I had the same proplem. Here is my code:
The index of my plugin (index.js ; Nofification.vue is a classical Vue component):
import Notifications from './Notifications.vue'
const NotificationStore = {
state: [], // here the notifications will be added
settings: {
overlap: false,
horizontalAlign: 'center',
type: 'info',
timeout: 5000,
...
},
setOptions(options) {
this.settings = Object.assign(this.settings, options)
},
removeNotification(timestamp) {
...
},
addNotification(notification) {
...
},
notify(notification) {
...
},
}
const NotificationsPlugin = {
install(Vue, options) {
const app = new Vue({
data: {
notificationStore: NotificationStore,
},
methods: {
notify(notification) {
this.notificationStore.notify(notification)
},
},
})
Vue.prototype.$notify = app.notify
Vue.notify = app.notify
Vue.prototype.$notifications = app.notificationStore
Vue.component('Notifications', Notifications)
if (options) {
NotificationStore.setOptions(options)
}
},
}
export default NotificationsPlugin
Here I call my plugin and inject it in Nuxt:
import Notifications from '~/components/NotificationPlugin'
Vue.use(Notifications)
export default (context, inject) => {
inject('notify', Vue.notify)
}
In my case, I use it in another plugin (nuxtjs axios).
import NOTIFICATIONS from '~/constants/notifications'
export default function ({ error, $axios, app }) {
// Using few axios helpers (https://axios.nuxtjs.org/helpers):
$axios.onError((axiosError) => {
// eslint-disable-next-line no-console
console.log('Axios: An error occured! ', axiosError, axiosError.response)
if (process.server) {
...
} else {
app.$notify({
message: 'Mon message',
timeout: NOTIFICATIONS.DEFAULT_TIMEOUT,
icon: 'tim-icons icon-spaceship',
horizontalAlign: NOTIFICATIONS.DEFAULT_ALIGN_HORIZONTAL,
verticalAlign: NOTIFICATIONS.DEFAULT_ALIGN_VERTICAL,
type: 'success',
})
console.log('PRINT ERROR')
return Promise.resolve(true)
}
})
}
As I injected it, I think I could have done export default function ({ error, $axios, app, $notify }) { and directly use $notify (and not the app.$notify).
If you want a better understanding, feel free to consult #nuxtjs/toast which works the same way:
https://github.com/nuxt-community/community-modules/blob/master/packages/toast/plugin.js
And the matching Vue component:
https://github.com/shakee93/vue-toasted/blob/master/src/index.js
Good luck, this is not easy stuff. I'll try to add something easier to understand in the docs!
you can find in this package https://www.npmjs.com/package/vue-toasted
installation
npm install vue-toasted --save
make a file as name toast.js in plugin folder
toast.js
import Vue from 'vue';
import Toasted from 'vue-toasted';
Vue.use(Toasted)
add this plugin to nuxt.config.js
plugins: [
{ src: '~/plugins/toast', ssr: false },
],
now you able to use in your methods like this
this.$toasted.show('hello i am your toast')
hope this helps

share a method of use axios globally standard for nuxtjs?

i want use it for all components and pages and my config present :
~/plugins/axios
import axios from 'axios'
export default axios.create({
baseURL: 'http://127.0.0.1:3001/'
})
but with this way , i must import axios from '~/plugins/axios' in components and pages
i want use something choise for like this :
this.$axios.post('url',data).then(res=>{
// do something in here
}).catch({
// do something in here
})
and no need import more axios
I recommend you to use the official "Axios Module" for Nuxt.js: https://github.com/nuxt-community/axios-module
npm install #nuxtjs/axios
First, you can set your baseURL in the nuxt.config.js or in an env variable (see https://axios.nuxtjs.org/options):
modules: [
'#nuxtjs/axios'
],
axios: {
baseURL: 'http://127.0.0.1:3001/' // or, Environment variable API_URL_BROWSER can be used to override browserBaseURL.
}
Then in <page>.vue, no more import, axios is injected in the app var (see https://axios.nuxtjs.org/usage):
<script>
export default {
asyncData ({ app }) {
app.$axios.$get(`/api/users`).then(
// do something in here
);
//...
}
}
</script>
Finally, you can handle errors globally with a custom plugin (see https://axios.nuxtjs.org/extend)
$axios.onError(error => {
// do something in here
})

Can't set Authentication header for Apollo client

I'm working on a Laravel application that uses React and Redux on the client side, with the React preset and Mix. I've decided to try out GraphQL for the API rather than the usual REST API approach and it's working OK so far. However, I've now got stuck.
I'm using Apollo as my HTTP client since it's built for working with GraphQL. In the past I've used JWT Auth for securing APIs, so naturally I've gone for that approach here too, since implementation is just a case of adding an appropriate header. I've followed the instruction on setting headers with Apollo, but the headers aren't getting set. Here's the JS file in question:
import LinkList from './components/LinkList';
import React from 'react';
import ReactDOM from 'react-dom';
import {Container} from './container';
import {createStore} from 'redux';
import reducer from './reducer';
import {Provider} from 'react-redux';
import {fromJS} from 'immutable';
import ApolloClient from 'apollo-boost';
import gql from 'graphql-tag';
import { createHttpLink } from 'apollo-link-http';
import { setContext } from 'apollo-link-context';
import { InMemoryCache } from 'apollo-cache-inmemory';
const httpLink = createHttpLink({
uri: window.initialData.graphql_route
});
const authLink = setContext((_, { headers }) => {
const token = window.initialData.jwt;
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
}
}
});
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
});
client.query({
query: gql`{
links {
id
title
link
}}`
}).then(result => console.log(result));
const store = createStore(
reducer,
fromJS(window.initialData),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
if (document.getElementById('list')) {
ReactDOM.render(
<Provider store={store}>
<Container />
</Provider>,
document.getElementById('list')
);
}
I populate window.initialData in the view, and that contains the necessary data, including the JWT token as window.initialData.jwt. Setting a breakpoint inside the definition of authLink does nothing, implying that it never gets called.
Any idea what's gone wrong? I've followed the examples in the documentation pretty closely, so all I can think of is that they might be put of date.
Info: Don't save your token in the localStorage Is it safe to store a JWT in localStorage with ReactJS?
You are using the ApolloClient from 'apollo-boost', but your token configuration is for another ApolloClient, the { ApolloClient } from 'apollo-client'.
If you want to save the token using the ApolloClient from apollo-boost:
const client = new ApolloClient({
uri: ...,
request: async operation => {
const token = localStorage.getItem('token');
operation.setContext({
headers: {
authorization: token ? `Bearer ${token}` : ''
}
});
}
});
Apollo Boost migration

Meteor can't subscribe to TAPi18n.Collection using TAPi18n.subscribe

I am using Meteor 1.5 and I am trying to subscribe to an i18n collection using these packages :
TAP:i18n
TAP:i18n-db
I ran meteor create --full <appname> to have the full scaffolded app.
Then I removed insecure and autopublish packages and added aldeed:simple-schema, audit-argument-checks and mdg:validated-method as recommended security mesures.
// imports/startup/server/fixtures.js
import { Meteor } from 'meteor/meteor';
import { Links } from '../../api/links/links.js';
Meteor.startup(() => {
// if the Links collection is empty
if (Links.find().count() === 0) {
const data = [
{
title: 'Do the Tutorial',
url: 'https://www.meteor.com/try',
i18n: {
'fr': {
title: 'FR Do the Tutorial',
},
},
createdAt: new Date(),
},
{
...
},
];
data.forEach(link => Links.insert(link));
}
});
// imports/api/links/links.js
import { Mongo } from 'meteor/mongo';
export const Links = new TAPi18n.Collection('links');
// imports/api/links/server/publications.js
import { Meteor } from 'meteor/meteor';
import { TAPi18n } from 'meteor/tap:i18n';
import { Links } from '../links.js';
TAPi18n.publish('links.all', function () {
return Links.i18nFind();
});
// client/main.js
import { TAPi18n } from 'meteor/tap:i18n';
import '/imports/startup/client';
import '/imports/startup/both';
Meteor.startup(function() {
TAPi18n.setLanguage('en');
});
// imports/ui/components/info/info.js
import { Links } from '/imports/api/links/links.js';
import { Meteor } from 'meteor/meteor';
import { TAPi18n } from 'meteor/tap:i18n';
import './info.html';
Template.info.onCreated(function () {
TAPi18n.subscribe('links.all');
});
Template.info.helpers({
links() {
return Links.find({});
},
});
...
In Chrome console using Meteor Dev-Tool, I can see this :
Chrome Meteor Dev-Tool screenshot
Basically it says unsubscribed from links.all (unrecognized subscription)
In the server console, I can see this :
Meteor Server Console
I did some work to include check statement in links.js above but even when I check all fields, the app can't subscribe to the publication.
Any idea or help would be much appreciated.
The packages are not mandatory for me if there is a better example/repo somewhere I can actually look at.
I thought you could not mix them up together. Use either TAP:i18n-db or TAP:i18n.
For examples have a look at the git repositories:
https://github.com/TAPevents/tap-i18n
https://github.com/TAPevents/tap-i18n-db
There are several examples you can have a look and decide to use only one of the packages.

Custom authenticator with Ember simple auth + Ember CLI

I'm trying to write a custom authenticator, similar to the one from this example in the docs. The goal is to be able to retrieve the currently logged in user via session.user.
I'm using Ember CLI, so in initializers/authentication.js I have
import Ember from 'ember';
var customAuthenticator = Ember.SimpleAuth.Authenticators.Devise.extend({
authenticate: function(credentials) {
debugger;
}
});
export default {
name: 'authentication',
initialize: function(container, application) {
Ember.SimpleAuth.Session.reopen({
user: function() {
var userId = this.get('user_id');
if (!Ember.isEmpty(userId)) {
return container.lookup('store:main').find('user', userId);
}
}.property('userId')
});
// register the custom authenticator so the session can find it
container.register('authenticator:custom', customAuthenticator);
Ember.SimpleAuth.setup(container, application, {
routeAfterAuthentication: 'landing-pages',
authorizerFactory: 'ember-simple-auth-authorizer:devise'
});
}
};
When I try to authenticate, I get the following error:
TypeError: Cannot read property 'authenticate' of undefined
at __exports__.default.Ember.ObjectProxy.extend.authenticate
Any idea why?
As of Simple Auth 0.6.4, you can now do something like:
index.html:
window.ENV['simple-auth'] = {
authorizer: 'simple-auth-authorizer:devise',
session: 'session:withCurrentUser'
};
initializers/customize-session.js:
import Ember from 'ember';
import Session from 'simple-auth/session';
var SessionWithCurrentUser = Session.extend({
currentUser: function() {
var userId = this.get('user_id');
if (!Ember.isEmpty(userId)) {
return this.container.lookup('store:main').find('user', userId);
}
}.property('user_id')
});
export default {
name: 'customize-session',
initialize: function(container) {
container.register('session:withCurrentUser', SessionWithCurrentUser);
}
};
You would need to do something like this:
Em.SimpleAuth.Authenticators.OAuth2.reopen
serverTokenEndpoint: "http://myapp.com/token"
authenticate: (credentials) ->
new Em.RSVP.Promise (resolve, reject) =>
data =
grant_type: "password"
username: credentials.identification
password: credentials.password
#makeRequest(data).then (response) =>
# success call
, (xhr, status, error) ->
# fail call
What I think might be happening is that you are registering the authenticator with the application and not the authenticator itself?
The problem is that the AMD build does not currently automatically register the extension libraries' components (see https://github.com/simplabs/ember-simple-auth/issues/198). I'll change that in the next release and will probably also adopt the documentation to be more focussed on the AMD build instead of the browserified version. For the moment you'd have to run this in your initializer
container.register(
'ember-simple-auth-authorizer:devise',
Ember.SimpleAuth.Authorizers.Devise
);
container.register(
'ember-simple-auth-authenticator:devise',
Ember.SimpleAuth.Authenticators.Devise
);