Retrieving object data from a service in Angular 2 - javascript

I'm trying to retrieve data from my service function, but am running into issues. My LandingPage component code, shown below, sends a keystroke to my service function, which then returns an object full of data.
But I cannot get the service object to return to my LandingPage. Here is how I create my service:
task.service.ts
addKey(keystroke) {
const query = "https://api.themoviedb.org/3/search/tv?api_key=";
fetch(query + key + '&language=en-US&query=' + keystroke)
.then((show) => {
show.json().then((obj) => {
// grab the items we want from the response
let resultItems = obj.results.map((show, index) => {
return {
id: show.id,
poster: show.poster_path,
rating: show.vote_average,
backdrop: show.backdrop_path,
};
});
// return our newly formed object
return { data: resultItems }
});
});
}
Here is where I am trying to receive the service data, in my:
landingpage.component.ts
getKey(keystroke) {
this.TaskService.addKey(keystroke)
.subscribe(res => {
this.shows = res.data; // trying to receive service info here
});
}
When I try to build, I receive the following error in my LandingPage component:
Property 'subscribe' does not exist on type 'void'.
I've tried using map instead of subscribe, but it returns a similar error.
How can I send the object result from my service, to my component?

It looks like you're missing a return in your service method, I've also changed to using http from our discussion in the comments:
addKey(keystroke): Observable<any> {
const query = "https://api.themoviedb.org/3/search/tv?api_key=";
return this.http.get(query + key + '&language=en-US&query=' + keystroke)
.map(show => {
show.json().then((obj) => {
// grab the items we want from the response
let resultItems = obj.results.map((show, index) => {
return {
id: show.id,
poster: show.poster_path,
rating: show.vote_average,
backdrop: show.backdrop_path,
};
});
// return our newly formed object
return { data: resultItems }
});
});
}
If you really want to use fetch you can if you:
Set the method return signature to Promise<any>
Use then instead of map in the service
Use then instead of subscribe in the component

Related

angular data modify before send the service

I need to modify my object. please check below function
registerCus(item) {
this.customer.code = 'B001';
this.customer.avCode = 'L01';
this.customer.ageCode = 'A1';
this.registrationService.customerRequest(item).subscribe(data => {
},
error => {
});
}
The item, included 3 values: code, avCode, ageCode. When I send the 'item' all three values pass to the service . According to my requirement I need to send only code and avCode. how can I modify 'item' before pass to service.
I am trying to do something like this,
registerCus(item) {
item = this.customer.code, this.customer.avCode;
this.registrationService.customerRequest(item).subscribe(data => {
},
error => {
});
}
You can use object de-structuring to achieve this behaviour without making any change in the code. You do this in your service method customerRequest;
customerRequest ({code, avCode}) {
console.log(code, avCode);
}
Learn more about destructuring in JS.
If item and customer are different objects:
registerCus(item) {
item.code = this.customer.code;
item.avCode = this.customer.code;
this.registrationService.customerRequest(item).subscribe(data => {
},
error => {
});
}
Otherwise you can use Object de-structuring

Unable to set Vue.js data values inside axios response

I have created an axios request to my api for two routes. Using the response data I sort posts into the correct columns inside an array. This all works as it should but then when I come to assigning the value of this array to an array inside data() i get the following error;
TypeError: Cannot set property 'boardPosts' of null
at eval (SummaryBoard.vue?2681:90)
at wrap (spread.js?0df6:25)
So I figured maybe something was wrong with the array I was trying to assign. So I tried to assign boardPosts a simple string value and I still get the same error. Why can I not set the value of boardPosts inside my axios response?
my code;
import axios from 'axios';
export default {
name: 'SummaryBoard',
data() {
return {
boardPosts: '',
}
},
created() {
this.getBoardData();
},
methods:
getBoardData() {
function getBoardColumns() {
return axios.get('http://localhost:5000/api/summary-board/columns');
}
function getBoardPosts() {
return axios.get('http://localhost:5000/api/summary-board/posts');
}
axios.all([getBoardColumns(), getBoardPosts()])
.then(axios.spread(function(columnData, postData) {
let posts = postData.data;
// add posts array to each object
let columns = columnData.data.map(obj => ({...obj, posts: []}));
posts.forEach((post) => {
// If column index matches post column index value
if(columns[post.column_index]){
columns[post.column_index].posts.push(post);
}
});
console.log(columns);
this.boardPosts = 'hello';
}))
.catch(error => console.log(error));
}
}
}
That's because you're using not using an arrow function in axios.spread(...). This means that you do not preserve the lexical this from the VueJS component, as function() {...} will create a new scope for itself. If you change it to use arrow function, then the this in the callback will refer to your VueJS component instance:
axios.all([getBoardColumns(), getBoardPosts()])
.then(axios.spread((columnData, postData) => {
// Rest of the logic here
}))
.catch(error => console.log(error));

[] vs [{...}] in browser tools, while both having same objects

If you look at the picture both arrays consist of same kind of object. first I create it with empty data as placeholder, but second one I create it with data coming from server.
writeValue(v: any) {
console.log('aaa');
console.log(v);
console.log('aaa');
this.form = new FormArray([]);
for (const value of v) {
console.log('bbb');
console.log(value);
console.log('bbb');
this.form.push(new FormControl(value));
}
this.form.valueChanges.subscribe(res => {
if (this.onChange) {
this.onChange(this.form.value);
}
});
}
for first case it goes through all of the writeValue code, for second one it doesn't go through the for(const values of v) code. why is this happening? when I print them out they seem to be the same other than one difference [{...}] vs [] in browser tools.
If you want to see how I create them. the first one is routes and the second one is routeslocal. I put them in angular formcontrol, and thats how it gets to writeValue via controlvalueaccessor. If you want to know how it works you could check my previous question here. there is more code, but it doesn't include the service.
ngOnInit() {
const routes: any[] = [];
routes.push({ ...dataI });
this.requestForm = this.fb.group({
statusId: null,
requestVehicles: this.fb.array([
this.fb.group({
garageId: 0,
routes: new FormControl(routes),
endDateTime: 0,
})
])
});
if (this.data.isEdit) {
this.Title = 'Edit';
this.data.fService.getRequest(this.data.requestId).subscribe(thisRequest => {
this.requestForm = this.fb.group({
statusId: thisRequest.status,
requestVehicles: this.fb.array([
])
});
thisRequest.requestVehicles.forEach((element, index) => {
const routeslocal: any[] = [];
element.routes.forEach((elementt, indexx) => {
this.data.fService.getAddressPoint(elementt).subscribe(sbed => {
const newRoute = {
addressPointId: sbed.addressPointId,
municipalityId: sbed.municipalityId,
regionId: sbed.regionId,
rvId: element.rvId,
sequenceNumber: indexx,
settlementId: sbed.settlementId,
regionName: sbed.regionName,
municipalityName: sbed.municipalityName,
settlementName: sbed.settlementName,
description: sbed.description,
};
routeslocal.push({...newRoute});
});
});
this.requestVehicles.push(this.fb.group({
endDateTime: new Date(element.endDateTime),
garageId: element.garageId,
routes: new FormControl(routeslocal),
}));
});
});
});
});
}
}
The opening line, [] or [{}], is immediately drawn in the console.
In the case of [], there was nothing in the array at logging time, so the browser draw it as an empty array. But the data was present when you looked at it and clicked on the small triangle, later.
You can reproduce this behavior with this code in your console:
;(function(){ let arr=[]; setTimeout(()=>{ arr[0] = {b:3}; }); return arr;})()
So the difference you saw is related to the (a)synchronicity of array filling.
Vato, you has two functions in your service:getRequest(requestId) and getAddressPoint(requestVehicles). The idea is return a whole object. You can create the function in the own service or in the component. I'd like in the service, and that return an objservable. You must use forkJoin and swithMap So . It's for me impossible check if work
**Update, see the stackblitz
getFullRequest(id): Observable<any> {
return this.getRequest(id).pipe(
switchMap((request: any) => {
//here you has the request. We create an array of observables
return forkJoin(
request.requestVehicles.map(
(r: any) => this.getAddressPoint(r))).pipe(map((res: any[]) => {
res.forEach((x: any, index: number) => {
x.sequenceNumber = index
})
return {
statusId: request.statusID,
routes: res
}
})
)
}))
}
then, in your component
if (this.data.isEdit) {
this.Title = 'Edit';
this.data.fService.getFullRequest(this.data.requestId).subscribe(thisRequest => {
this.requestForm = this.fb.group({
statusId: thisRequest.status,
requestVehicles: thisRequest.routes
});
Update 2 briefly explain about switchMap and forkJoin.
When we make this.getRequest(id) we received in request an object. In this object we has in requestVehicles an array (can be an array of objects or an array of numbers -or strings-). With each element of this array we can make a call, But instead of make the calls one to one, we want to make all these together. For this we use forkJoin. forkJoin received an array of observables and, in subscribe received the response in an array
//if we has an observable like:
getValue(id:number):Observable<any>{
return of({one:id})
}
//and an array like
myArray=[1,2]
//and an array of response whe we can store the responses
response:any[]
//we can do
for (let id of myArray)
{
this.getValue(id).susbcribe(res=>{
this.response.push(res)
})
}
//or
observables:any[]
for (let id of myArray)
{
this.observables.push(this.getValue(id))
}
forkJoin(this.observables).subscribe((res;any[])=>{
//in res[0] we have the result of this.getValue(1)
//in res[1] we have the result of this.getValue(2)
//so, simply
this.response=res
})
//or in a compact way
//with each element of the array
observables=myArray.map(x=>this.getValues(x))
forkJoin(this.observables).subscribe((res;any[])=>{
this.response=res
})
Well, there are two problems more. We want add a new propertie "sequenceNumber" to all the response. So we use res.forEach(...) to add the property. And we want return an object with somes properties of our original request (statusID) and in "routes" the array with the response. So we use map to transform the response. In our simple example above
//not return simple {one:1}
//return {id:1,one:1}
getResponse(2).pipe.map(res=>{
return {
id:1,
one:res.one
}
}

Apollo Client: Upsert mutation only modifies cache on update but not on create

I have an upsert query that gets triggered on either create or update. On update, Apollo integrates the result into the cache but on create it does not.
Here is the query:
export const UPSERT_NOTE_MUTATION = gql`
mutation upsertNote($id: ID, $body: String) {
upsertNote(id: $id, body: $body) {
id
body
}
}`
My client:
const graphqlClient = new ApolloClient({
networkInterface,
reduxRootSelector: 'apiStore',
dataIdFromObject: ({ id }) => id
});
The response from the server is identical: Both id and body are returned but Apollo isn't adding new ids into the data cache object automatically.
Is it possible to have Apollo automatically add new Objects to data without triggering a subsequent fetch?
Here is what my data store looks like:
UPDATE
According to the documentation, the function updateQueries is supposed to allow me to push a new element to my list of assets without having to trigger my origin fetch query again.
The function gets executed but whatever is returned by the function is completely ignored and the cache is not modified.
Even if I do something like this:
updateQueries: {
getUserAssets: (previousQueryResult, { mutationResult }) => {
return {};
}
}
Nothing changes.
UPDATE #2
Still can't get my assets list to update.
Inside updateQueries, here is what my previousQueryResult looks like:
updateQueries: {
getUserAssets: (previousQueryResult, { mutationResult }) => {
return {
assets: []
.concat(mutationResult.data.upsertAsset)
.concat(previousQueryResult.assets)
}
}
}
But regardless of what I return, the data store does not refresh:
For reference, here is what each asset looks like:
Have you followed the example here ?
I would write the updateQueries in the mutate like this:
updateQueries: {
getUserAssets: (previousQueryResult, { mutationResult }) => {
const newAsset = mutationResult.data.upsertAsset;
return update(prev, {
assets: {
$unshift: [newAsset],
},
});
},
}
Or with object assign instead of update from immutability-helper:
updateQueries: {
getUserAssets: (previousQueryResult, { mutationResult }) => {
const newAsset = mutationResult.data.upsertAsset;
return Object.assign({}, prev, {assets: [...previousQueryResult.assets, newAsset]});
},
}
As you state in your update, you need to use updateQueries in order to update the queries associated with this mutation. Although your question does not state what kind of query is to be updated with the result of the mutation, I assume you have something like this:
query myMadeUpQuery {
note {
id
body
}
}
which should return the list of notes currently within your system with the id and body of each of the notes. With updateQueries, your callback receives the result of the query (i.e. information about a newly inserted note) and the previous result of this query (i.e. a list of notes) and your callback has to return the new result that should be assigned to the query above.
See here for an analogous example. Essentially, without the immutability-helper that the given example uses, you could write your updateQueries callback as follows:
updateQueries: {
myMadeUpQuery: (previousQueryResult, { mutationResult }) => {
return {
note: previousQueryResult.note(mutationResult.data.upsertNode),
};
}
}

Trying to post object with parameters - angular js

I am trying to do a http get in angular like this:
$http
.get(some url, {
params: {
description: params.description,
from: params.from,
to: params.to
}
})
.success(function (data,status) {
$scope.info_show = data
});
here's the thing, the params object parameters are set based in user input, so if the user hasn't inputted anything for the from property (some input text fielt) it will be undefined.
my problem is that I can't just pass the params object, because it doesn't filter and if I pass undefined on even one of the properties then the web service by default will return everything, could someone show me a way of dynamically doing this?
You could use a function to filter the params object.
This one receives a list of params/properties you want to filter and the src object to filter from:
var filterParams = function(params, src) {
var result = {};
angular.forEach(params, function(p) {
if (angular.isDefined(src[p])) {
result[p] = src[p];
}
});
return result;
};
And then use it like this:
$http.get(some url, {
params: filterParams(['from', 'to', 'description'], params)
})
.success(function (data,status) {
$scope.info_show = data
});

Categories