Vuejs function with multiple data - laravel

I have two data table in vue app.
Cash [code, description,cash]
Upload [bank, id]
For my update function, i need to take [bank, id] from upload and [cash] from cash. i don't know how, can someone help please ? Thank you. This is my code
This is my vuejs
var app = new Vue({
el: '#app',
data: {
cash: {
codeentry: '',
description: '',
cash: '',
},
upload: {
bank: '',
id: '',
},
},
methods: {
updateBank: function () {
axios.put('/updatebank', this.upload, this.cash)
.then(response => {
if (response.data.etat) {
this.upload.id = response.data.etat.id
this.upload.bank = response.data.etat.bank
this.cash.cash = response.data.etat.cash
}
})
.catch(error => {
console.log('errors: ', error)
})
},
}
});
My route :
Route::put('/updatebank', 'CoinController#updateBank');
Controller :
public function updateBank(Request $request)
{
$coin = Coin::findOrFail($request->id);
$coin->bank = ($request->bank - $request->cash);
$coin->save();
}
When i execute my function and see the report. Only this.upload is token in consideration.

If you mean to have the two data in one object, you can make a new object from the two objects
Es6 Example:
const {bank,id} = this.upload;
const {cash} = this.cash;
const my_data = {
bank, id, cash
}
Older Js example
var my_data = {
cash: this.cash.cash,
bank: this.upload.bank,
id: this.upload.id,
}
Otherwise, if you want to have both in the request as separate objects then wrap around them {}
var my_data = {
upload: this.upload,
cash: this.cash
}
Finally:
axios.put('/updatebank', my_data)
...
Update: It appears you don't want to merge those objects as different sub-object so your updateBank method would be like so:
updateBank: function () {
const my_data = {
cash: this.cash.cash,
bank: this.upload.bank,
id: this.upload.id,
};
axios.put('/updatebank', my_data)
.then(response => {
if (response.data.etat) {
this.upload.id = response.data.etat.id
this.upload.bank = response.data.etat.bank
this.cash.cash = response.data.etat.cash
}
})
.catch(error => {
console.log('errors: ', error)
});
}
Just a side observation, are you sure the this in the response references your Vue object?

Related

How to get random records from Strapi content API

I have records in strapi. I am using strapi content API. In my front-end, I need to display only 2 records randomly. For limiting, I have used limit query from content API. But random fetching what keyword I need to use. The official documentation doesn't provide any details regarding this - https://strapi.io/documentation/v3.x/content-api/parameters.html#available-operators
There's no official Strapi API parameter for random. You have to implement your own. Below is what I've done previously, using Strapi v3:
1 - Make a service function
File: api/mymodel/services/mymodel.js
This will contain our actual random query (SQL), and wrapping it in a service is handy because it can be used in many places (cron jobs, inside other models, etc).
module.exports = {
serviceGetRandom() {
return new Promise( (resolve, reject) => {
// There's a few ways to query data.
// This example uses Knex.
const knex = strapi.connections.default
let query = knex('mydatatable')
// Add more .select()'s if you want other fields
query.select('id')
// These rules enable us to get one random post
query.orderByRaw('RAND()')
query.limit(1)
// Initiate the query and do stuff
query
.then(record => {
console.log("getRandom() record: %O", record[0])
resolve(record[0])
})
.catch(error => {
reject(error)
})
})
}
}
2 - Use the service somewhere, like a controller:
File: api/mymodel/controllers/mymodel.js
module.exports = {
//(untested)
getRandom: async (ctx) => {
await strapi.services.mymodel.serviceGetRandom()
.then(output => {
console.log("getRandom output is %O", output.id)
ctx.send({
randomPost: output
}, 200)
})
.catch( () => {
ctx.send({
message: 'Oops! Some error message'
}, 204) // Place a proper error code here
})
}
}
3 - Create a route that points to this controller
File: api/mymodel/config/routes.json
...
{
"method": "GET",
"path": "/mymodelrandom",
"handler": "mymodel.getRandom",
"config": {
"policies": []
}
},
...
4 - In your front-end, access the route
(However you access your API)
e.g. ajax call to /api/mymodelrandom
There is no API parameter for getting a random result.
So: FrontEnd is the recommended solution for your question.
You need to create a random request range and then get some random item from this range.
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
const firstID = getRandomInt(restaurants.length);
const secondID = getRandomInt(3);
const query = qs.stringify({
id_in:[firstID,secondID ]
});
// request query should be something like GET /restaurants?id_in=3&id_in=6
One way you can do this reliably is by two steps:
Get the total number of records
Fetch the number of records using _start and _limit parameters
// Untested code but you get the idea
// Returns a random number between min (inclusive) and max (exclusive)
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
const { data: totalNumberPosts } = await axios.get('/posts/count');
// Fetch 20 posts
const _limit = 20;
// We need to be sure that we are not fetching less than 20 posts
// e.g. we only have 40 posts. We generate a random number that is 30.
// then we would start on 30 and would only fetch 10 posts (because we only have 40)
const _start = getRandomArbitrary(0, totalNumberPosts - _limit);
const { data: randomPosts } = await axios.get('/posts', { params: { _limit, _start } })
The problem with this approach is that it requires two network requests but for my needs, this is not a problem.
This seem to work for me with Strapi v.4 REST API
Controller, Get 6 random entries
"use strict";
/**
* artwork controller
*/
const { createCoreController } = require("#strapi/strapi").factories;
module.exports = createCoreController("api::artwork.artwork", ({ strapi }) => {
const numberOfEntries = 6;
return {
async random(ctx) {
const entries = await strapi.entityService.findMany(
"api::artwork.artwork",
{
populate: ["image", "pageHeading", "seo", "socialMedia", "artist"],
}
);
const randomEntries = [...entries].sort(() => 0.5 - Math.random());
ctx.body = randomEntries.slice(0, numberOfEntries);
},
};
});
Route
random.js
"use strict";
module.exports = {
routes: [
{
method: "GET",
path: "/artwork/random",
handler: "artwork.random",
config: {
auth: false,
},
},
],
};
API
http://localhost:1337/api/artwork/random
To match default data structure of Strapi
"use strict";
/**
* artwork controller
*/
const { createCoreController } = require("#strapi/strapi").factories;
module.exports = createCoreController("api::artwork.artwork", ({ strapi }) => {
const numberOfEntries = 6;
return {
async random(ctx) {
const entries = await strapi.entityService.findMany(
"api::artwork.artwork",
{
populate: ["image", "pageHeading", "seo", "socialMedia", "artist"],
}
);
const randomEntries = [...entries]
.sort(() => 0.5 - Math.random())
.slice(0, numberOfEntries);
const structureRandomEntries = {
data: randomEntries.map((entry) => {
return {
id: entry.id,
attributes: entry,
};
}),
};
ctx.body = structureRandomEntries;
},
};
});
There is also a random sort plugin.
https://www.npmjs.com/package/strapi-plugin-random-sort
This seem to work for me with Strapi v4.3.8 and graphql
src/index.js
"use strict";
module.exports = {
register({ strapi }) {
const extensionService = strapi.service("plugin::graphql.extension");
const extension = ({ strapi }) => ({
typeDefs: `
type Query {
randomTestimonial: Testimonial
}
`,
resolvers: {
Query: {
randomTestimonial: async (parent, args) => {
const entries = await strapi.entityService.findMany(
"api::testimonial.testimonial"
);
const sanitizedRandomEntry =
entries[Math.floor(Math.random() * entries.length)];
return sanitizedRandomEntry;
},
},
},
resolversConfig: {
"Query.randomTestimonial": {
auth: false,
},
},
});
extensionService.use(extension);
},
bootstrap({ strapi }) {},
};
graphql query:
query GetRandomTestimonial {
randomTestimonial {
__typename
name
position
location
description
}
}
generate random testimonial on route change/refresh
https://jungspooner.com/biography

useState depending on other state

I have this useSiren hook that should update its state with the incoming json argument but it doesnt.
On the first call the json is an empty object, because the fetch effect has not been run yet.
On the second call its also an empty object (triggered by loading getting set to true in App)
And on the third call its filled with valid data. However, the valid data is not applied. The state keeps its initial value.
I guess somehow setSiren must be called to update it, since initial state can only be set once. But how would I do that? Who should call `setSiren?
import { h, render } from 'https://unpkg.com/preact#latest?module';
import { useEffect, useState, useCallback } from 'https://unpkg.com/preact#latest/hooks/dist/hooks.module.js?module';
import htm from "https://unpkg.com/htm#latest/dist/htm.module.js?module";
const html = htm.bind(h);
function useFetch({
method = "GET",
autoFetch = true,
href,
body
}) {
const [loading, setLoading] = useState(false)
const [error, setError] = useState()
const [response, setResponse] = useState()
const [isCancelled, cancel] = useState()
const [json, setJson] = useState({})
const sendRequest = async payload => {
try {
setLoading(true)
setError(undefined)
const response = await fetch(href.replace("http://", "https://"), {
method
})
const json = await response.json()
if (!isCancelled) {
setJson(json)
setResponse(response)
}
return json
} catch (err) {
if (!isCancelled) {
setError(err)
}
throw err
} finally {
setLoading(false)
}
}
if (autoFetch) {
useEffect(() => {
sendRequest(body)
return () => cancel(true)
}, [])
}
return [{
loading,
response,
error,
json
},
sendRequest
]
}
function useSiren(json) {
const [{ entities = [], actions = [], links, title }, setSiren] = useState(json)
const state = (entities.find(entity => entity.class === "state")) || {}
return [
{
title,
state,
actions
},
setSiren
]
}
function Action(props) {
const [{ loading, error, json }, sendRequest] = useFetch({ autoFetch: false, href: props.href, method: props.method })
const requestAndUpdate = () => {
sendRequest().then(props.onRefresh)
}
return (
html`
<button disabled=${loading} onClick=${requestAndUpdate}>
${props.title}
</button>
`
)
}
function App() {
const [{ loading, json }, sendRequest] = useFetch({ href: "https://restlr.io/toggle/0" })
const [{ state, actions }, setSiren] = useSiren(json)
return (
html`<div>
<div>State: ${loading ? "Loading..." : (state.properties && state.properties.value)}</div>
${actions.map(action => html`<${Action} href=${action.href} title=${action.title || action.name} method=${action.method} onRefresh=${setSiren}/>`)}
<button disabled=${loading} onClick=${sendRequest}>
REFRESH
</button>
</div>
`
);
}
render(html`<${App}/>`, document.body)
Maybe what you want to do is to update the siren state when the json param changes? You can use a useEffect to automatically update it.
function useSiren(json) {
const [{ entities = [], actions = [], links, title }, setSiren] = useState(json)
useEffect(() => { // here
setSiren(json)
}, [json])
const state = (entities.find(entity => entity.class === "state")) || {}
return [
{
title,
state,
actions
},
setSiren
]
}
The pattern mentioned by #awmleer is packaged in use-selector:
import { useSelectorValue } from 'use-selector';
const { entities=[], actions=[], title} = json;
const siren = useSelectorValue(() => ({
state: entities.find(entity => entity.class === 'state') || {},
actions,
title
}), [json]);
Disclosure I'm author and maintainer of use-selector

How can I return the data as multiple objects?

I set an empty array inside a state
const state = {
jobs: []
}
Inside the component, I dispatch an action and the code looks like this:
created(){
this.$store.dispatch('viewJobs');
}
The viewJobs actions looks like the following:
viewJobs: ({commit}) => {
axios.get('/api/jobs')
.then(res => {
const jobss = res.data;
console.log(jobss);
commit('LIST_JOBS', jobss);
})
.catch(error => console.log(error));
}
And then the mutations looks like this:
'LIST_JOBS'(state, jobss){
state.jobs.push(jobss);
}
From the laravel side, my controller looks like this:
$jobs = Employment::all();
return $jobs->toJson(JSON_PRETTY_PRINT);
When I load the page, am able to console log jobss, but the state does not get updated.
How can I successfully push the data to the state?
You are adding the entire array as a single element of state.jobs. Instead, you can use the Javascript spread operator, to push each element from the array:
state.jobs.push(...jobss)
Try to use response()->json()
return response()->json(Employment::all(),200);
and try use {jobss:jobss} in commit section
viewJobs: ({commit}) => {
axios.get('/api/jobs')
.then(res => {
const jobss = res.data;
console.log(jobss);
commit('LIST_JOBS', {jobss:jobss});
})
.catch(error => console.log(error));
}
Another way, your vuex store looks like this
// state
export const state = () => ({
items: []
})
// getters
export const getters = {
items: state => state.items
}
// mutations
export const mutations = {
SET_ITEMS (state, { items }) {
state.items = items
},
PUSH_ITEM (state, { item }) {
state.items.push(item)
},
UPDATE_ITEM (state, { index, item }) {
state.items[index] = item
},
DELETE_ITEM: (state, index) => {
state.items.splice(index.index, 1);
}
}
// actions
export const actions = {
setItems ({ commit }, { items }) {
commit('SET_ITEMS', { items })
},
pushItem ({ commit,state }, { item }) {
commit('PUSH_ITEM', { item })
},
deleteItem ({ commit,state }, { index }) {
commit('DELETE_ITEM', { index })
},
updateItem ({ commit,state }, { index,item }) {
commit('UPDATE_ITEM', { index,item })
},
}
Then in your component call your action
this.$axios.$get('/api/jobs')
.then(res => {
const jobss = res.data;
console.log(jobss);
this.$store.dispatch('your_store_name/setItems', {items:jobss});
})
.catch(error => console.log(error));

How can I test Observable.ajax (redux-observable)?

I have been playing with rxjs and redux-observable for the last few days and have been struggle to find a way to a test for Observable.ajax. I have the following epic which create a request to https://jsonplaceholder.typicode.com/,
export function testApiEpic (action$) {
return action$.ofType(REQUEST)
.switchMap(action =>
Observable.ajax({ url, method })
.map(data => successTestApi(data.response))
.catch(error => failureTestApi(error))
.takeUntil(action$.ofType(CLEAR))
)
}
where,
export const REQUEST = 'my-app/testApi/REQUEST'
export const SUCCESS = 'my-app/testApi/SUCCESS'
export const FAILURE = 'my-app/testApi/FAILURE'
export const CLEAR = 'my-app/testApi/CLEAR'
export function requestTestApi () {
return { type: REQUEST }
}
export function successTestApi (response) {
return { type: SUCCESS, response }
}
export function failureTestApi (error) {
return { type: FAILURE, error }
}
export function clearTestApi () {
return { type: CLEAR }
}
The code works fine when runs in browser but not when testing with Jest.
I have try,
1) Create a test based on https://redux-observable.js.org/docs/recipes/WritingTests.html. The store.getActions() returns only { type: REQUEST }.
const epicMiddleware = createEpicMiddleware(testApiEpic)
const mockStore = configureMockStore([epicMiddleware])
describe.only('fetchUserEpic', () => {
let store
beforeEach(() => {
store = mockStore()
})
afterEach(() => {
epicMiddleware.replaceEpic(testApiEpic)
})
it('returns a response, () => {
store.dispatch({ type: REQUEST })
expect(store.getActions()).toEqual([
{ type: REQUEST },
{ type: SUCCESS, response }
])
})
})
2) Create a test based on Redux-observable: failed jest test for epic. It returns with
Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
it('returns a response', (done) => {
const action$ = ActionsObservable.of({ type: REQUEST })
const store = { getState: () => {} }
testApiEpic(action$, store)
.toArray()
.subscribe(actions => {
expect(actions).to.deep.equal([
{ type: SUCCESS, response }
])
done()
})
})
Can someone point me out what is the correct way to test Observable.ajax ?
I would follow the second example, from StackOverflow. To make it work you'll need to make some minor adjustments. Instead of importing Observable.ajax in your epic file and using that reference directly, you need to use some form of dependency injection. One way is to provide it to the middleware when you create it.
import { ajax } from 'rxjs/observable/dom/ajax';
const epicMiddleware = createEpicMiddleware(rootEpic, {
dependencies: { ajax }
});
The object we passed as dependencies will be give to all epics as the third argument
export function testApiEpic (action$, store, { ajax }) {
return action$.ofType(REQUEST)
.switchMap(action =>
ajax({ url, method })
.map(data => successTestApi(data.response))
.catch(error => failureTestApi(error))
.takeUntil(action$.ofType(CLEAR))
);
}
Alternatively, you could not use the dependencies option of the middleware and instead just use default parameters:
export function testApiEpic (action$, store, ajax = Observable.ajax) {
return action$.ofType(REQUEST)
.switchMap(action =>
ajax({ url, method })
.map(data => successTestApi(data.response))
.catch(error => failureTestApi(error))
.takeUntil(action$.ofType(CLEAR))
);
}
Either one you choose, when we test the epic we can now call it directly and provide our own mock for it. Here are examples for success/error/cancel paths These are untested and might have issues, but should give you the general idea
it('handles success path', (done) => {
const action$ = ActionsObservable.of(requestTestApi())
const store = null; // not used by epic
const dependencies = {
ajax: (url, method) => Observable.of({ url, method })
};
testApiEpic(action$, store, dependencies)
.toArray()
.subscribe(actions => {
expect(actions).to.deep.equal([
successTestApi({ url: '/whatever-it-is', method: 'WHATEVERITIS' })
])
done();
});
});
it('handles error path', (done) => {
const action$ = ActionsObservable.of(requestTestApi())
const store = null; // not used by epic
const dependencies = {
ajax: (url, method) => Observable.throw({ url, method })
};
testApiEpic(action$, store, dependencies)
.toArray()
.subscribe(actions => {
expect(actions).to.deep.equal([
failureTestApi({ url: '/whatever-it-is', method: 'WHATEVERITIS' })
])
done();
});
});
it('supports cancellation', (done) => {
const action$ = ActionsObservable.of(requestTestApi(), clearTestApi())
const store = null; // not used by epic
const dependencies = {
ajax: (url, method) => Observable.of({ url, method }).delay(100)
};
const onNext = chai.spy();
testApiEpic(action$, store, dependencies)
.toArray()
.subscribe({
next: onNext,
complete: () => {
onNext.should.not.have.been.called();
done();
}
});
});
For the first way:
First, use isomorphic-fetch instead of Observable.ajax for nock support, like this
const fetchSomeData = (api: string, params: FetchDataParams) => {
const request = fetch(`${api}?${stringify(params)}`)
.then(res => res.json());
return Observable.from(request);
};
So my epic is:
const fetchDataEpic: Epic<GateAction, ImGateState> = action$ =>
action$
.ofType(FETCH_MODEL)
.mergeMap((action: FetchModel) =>
fetchDynamicData(action.url, action.params)
.map((payload: FetchedData) => fetchModelSucc(payload.data))
.catch(error => Observable.of(
fetchModelFail(error)
)));
Then, you may need an interval to decide when to finish the test.
describe("epics", () => {
let store: MockStore<{}>;
beforeEach(() => {
store = mockStore();
});
afterEach(() => {
nock.cleanAll();
epicMiddleware.replaceEpic(epic);
});
it("fetch data model succ", () => {
const payload = {
code: 0,
data: someData,
header: {},
msg: "ok"
};
const params = {
data1: 100,
data2: "4"
};
const mock = nock("https://test.com")
.get("/test")
.query(params)
.reply(200, payload);
const go = new Promise((resolve) => {
store.dispatch({
type: FETCH_MODEL,
url: "https://test.com/test",
params
});
let interval: number;
interval = window.setInterval(() => {
if (mock.isDone()) {
clearInterval(interval);
resolve(store.getActions());
}
}, 20);
});
return expect(go).resolves.toEqual([
{
type: FETCH_MODEL,
url: "https://test.com/assignment",
params
},
{
type: FETCH_MODEL_SUCC,
data: somData
}
]);
});
});
enjoy it :)

Avoid adding reactive properties to a Vue instance or its root $data at runtime - declare it upfront in the data option.

I am a bit confused using VueJS2. I added a few variables to the data container for sending it to my API. That works fine but Vue is throwing me a warning/error message which I don't know how to solve:
Avoid adding reactive properties to a Vue instance or its root $data
at runtime - declare it upfront in the data option.
var app = new Vue({
el: '#app',
data: {
incidentReference: '',
streetName: '',
latitude: '',
longitude: '',
featureTypeId: 1,
archived: 0
},
computed: {
href() {
return '#' + this.name.toLowerCase().replace(/ /g, '-');
}
},
mounted: function () {
this.getIncidents();
},
methods: {
onSubmit() {
axios.post('/api/v1/incidents', this.$data)
.then(response => alert('Success'))
.catch(error => {
console.log(error.response);
})
},
getIncidents: function() {
console.log('getIncidents');
var self = this;
axios.get('/api/v1/incidents').then(function(response) {
// set data on vm
console.log(response.data);
var incidentsReceived = response.data.data.map(function (incident) {
return incident;
});
Vue.set(self, 'incidents', incidentsReceived);
});
}
}
});
You're creating a new reactive property on the response of your API
Vue.set(self, 'incidents', incidentsReceived);
Not sure if you misspelled property's name or forget to create that property. Just use an existing property on you data section
Vue.set(self, 'incidentReference', incidentsReceived); //change property name
or
data: {
incidents: null, //or create this property
},
In my case during unit testing using Jest, I was setting selected but didn't have on component so got this error.
wrapper.setData({
selected: recipients,
});
So created the property on component and then it's working fine.
In the context of Jest & Vue Test Utils consider declaring data in component:
const Component = {
// ..
data() { return { abc: 'abc'; } }
};
const wrapper = mount(Component, { /*..*/ });
instead of
const Component = { /*..*/ };
const wrapper = mount(Component, { /*..*/ });
wrapper.setData({ abc: 'abc' });
await wrapper.vm.$nextTick();

Resources