Angular 5 HTTPClient not returning results for RouteResolver - angular5

I have to say HttpClient Observables, subscriptions etc are pretty hard/time consuming to get right.
I have been working on a problem for a while now and tearing my hair out. I have a service that I need to be able to perform a mapping function on.
loadAllSummary(organisationId: number) {
return this.http.get('/api/aircrafts/organisations/' + organisationId)
.pipe(
map(data => data.forEach(datum => {
console.log('why am i not getting here! ' + JSON.stringify(data));
return this.mapToSummary(datum);
}))
);
}
with the mapToSummary() method:
private mapToSummary(aircraft: Aircraft): IAircraftSummary {
const lastDate: Date = new Date(Math.max.apply(null, aircraft.workorders.map(function(e) {
return new Date(e.date);
})));
return new AircraftSummary({
lastWork: lastDate,
rego: aircraft.registration,
make: aircraft.make,
model: aircraft.model,
contact: (aircraft.owner.type.endsWith('primary')) ? aircraft.owner.principal : aircraft.operator.principal,
phone: (aircraft.owner.type.endsWith('primary')) ? aircraft.owner.contact.phone : aircraft.operator.contact.phone
});
}
Now, I need these summaries as input data to a view, so I borrowed code from the interwebs and created this ResolverService:
#Injectable()
export class AircraftsResolverService implements Resolve<IAircraftSummary[]> {
constructor(private service: AircraftService,
private router: Router) { }
resolve(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<IAircraftSummary[]> {
console.log('called AircraftsResolverService')
const id = route.params['id'];
if (isNaN(+id)) {
console.log(`Organisation id was not a number: ${id}`);
this.router.navigate(['/login']);
return Observable.of(null);
}
return this.service.loadAllSummary(+id)
.map(summaries => {
console.log(summaries)
if (summaries) {
return summaries;
}
console.log(`Summaries were not found: ${id}`);
this.router.navigate(['/organisations/', +id]);
return null;
})
.catch(error => {
console.log(`Retrieval error: ${error}`);
this.router.navigate(['/organisations/', +id]);
return Observable.of(null);
});
}
}
Which I then refer to in the ngOnInit call...
ngOnInit() {
this.currentUser = this.authenticationService.returnCurrentUser();
this.route.data
.subscribe(({aircrafts}) => {
this.aircrafts = aircrafts;
const id = +this.route.snapshot.paramMap.get('id');
console.log(' where are my aircraft!' + JSON.stringify(aircrafts));
this.ELEMENT_DATA = aircrafts;
this.displayedColumns = ['Last Work', 'Rego', 'Make', 'Model', 'Contact', 'Phone'];
this.dataSource = new MatTableDataSource(this.ELEMENT_DATA);
this.dataSource.sort = this.sort;
console.log(id);
if (id) {
this.organisationService.getById(id).subscribe(org => {
this.organisation = org;
});
} else {
console.log('its bad');
}
});
console.log(this.dataSource);
}
The console log under the subscribe is undefined and the console.logs under the service never get triggered. So once again, I find myself not understanding why subscription fire or not fire, or whatever it is that they do.
How do I get past this? thanks everyone.
EDIT: appears that the problem is actually in the ResolverService, I have been able to determine that the data service is getting the results and that they are correct. For some reason, the resolver service can't see them.

The answer was in the route resolver, or rather the app-routing-module. I should have included it in the question, because some of the angular saltys would have picked it up
I was trying to do this:.
{ path: 'organisations/:orgId/aircrafts/:id', component: AircraftsComponent, resolve: {aircrafts : AircraftsResolverService}, canActivate: [AuthGuard] },
But you can't, you have to do this:
{ path: 'organisations/aircrafts/:orgId/:id', component: AircraftsComponent, resolve: {aircrafts : AircraftsResolverService}, canActivate: [AuthGuard] },
results in very non-resty urls, but, hey, whatever works, right?

Related

To-dos don't update when I choose a to-do list

I have two components: TodoList and TodoListsList. They get their data from states in todos.js and todoLists.js modules accordingly. When I choose some to-do list, i.e mark it as active, TodoListsList is updated, but TodoLists isn't, thought the data is updated. Here's how I do it.
todoListsState and markAsActive() (todoLists.js):
import todos from '#/modules/todos.js'
// ... some code ...
const todoListsState = reactive({
todoLists: [],
todoListsAreLoading: false,
removedTodoListId: null,
editedTodoListId: null,
editedTodoListName: '',
baseTodoListsApiUrl: process.env.VUE_APP_BASE_TODO_LISTS_API_URL,
todoListCreationFormModalId: 'todoListCreationFormModal',
todoListNameChangeFormModalId: 'todoListNameChangeFormModal'
});
// ... some code ...
function markAsActive(value) {
let { close } = infoToast();
if (value) {
axios.post((todoListsState.baseTodoListsApiUrl + 'mark-as-active'), {
activatedTodoListId: value
}).then(function () {
getTodoLists();
const { getTodos } = todos();
getTodos();
}).catch(function () {
dangerToast('Failed to mark to-do list as active.');
}).finally(() => {
close();
});
}
}
todosState and getTodos() (todos.js):
const todosState = reactive({
todos: [],
activeTodoListId: 0,
removedTodoId: null,
editedTodoId: null,
editedTodoText: '',
todosAreLoading: false,
baseTodosApiUrl: process.env.VUE_APP_BASE_TODOS_API_URL,
todoAdditionFormModalId: 'todoAdditionFormModal',
todoEditFormModalId: 'todoEditFormModal'
});
// ... some code ...
async function getTodos() {
try {
todosState.todosAreLoading = true;
const response = await axios.get(todosState.baseTodosApiUrl);
todosState.activeTodoListId = response.data[0];
todosState.todos = response.data[1];
} catch (e) {
dangerToast('To-dos loading failed.');
} finally {
todosState.todosAreLoading = false;
}
}
How does todosState.todos look in console:
todosState.todos when Todos.vue is mounted:
It doesn't look like the array looses it's reactivity.
If you need something else to understand my question, feel free to ask. Help appreciated.
The problem is solved! I have just moved todosState out of
export default function () {}
and it works! Finally! This thread helped me a lot.

mapPropertyErrors seems to only return null

I can't seem to get the automatic error messages working. My configuration seems to be correct from what I've read online, yet the error always get's picked up in the catch after using the repository.save(entity) function. I'm specifically trying to get an error related to leaving the field empty but :required="true" doesn't seem to help. Could it be because they are translation fields? My entity is called suiteseven_usp.
I've got the following definition:
protected function defineFields(): FieldCollection
{
return new FieldCollection([
(new IdField('id', 'id'))->addFlags(new Required(), new PrimaryKey()),
(new TranslatedField('text'))->addFlags(new ApiAware(), new Required()),
(new TranslatedField('subtext'))->addFlags(new ApiAware(), new Required()),
new StringField('icon', 'icon'),
new StringField('type', 'type'),
new TranslationsAssociationField(UspTranslationDefinition::class, 'suiteseven_usp_id'),
]);
}
The following in computed: in my component:
...mapPropertyErrors('suiteseven_usp', [
'text',
'subtext'
]),
And this as one of the fields:
<sw-field
v-model="usp.text"
class="s7-usp-detail__text"
:label="$tc('s7-usp.detail.fieldTextLabel')"
:placeholder="$tc('s7-usp.detail.fieldTextPlaceholder')"
:disabled="!acl.can('usp.editor')"
:error="suitesevenUspTextError"
:required="true"
></sw-field>
This is my save function:
onSave() {
this.isLoading = true;
this.isSaveSuccessful = false;
return this.uspRepository.save(this.usp, Shopware.Context.api).then(() => {
this.isSaveSuccessful = true;
this.createNotificationSuccess({
title: this.$tc('global.default.success'),
message: this.$tc('s7-usp.detail.notificationSuccessMessage'),
});
if (!this.uspId) {
this.$router.push({name: 's7.usp.detail', params: {id: this.usp.id}});
}
this.uspRepository.get(this.usp.id, Shopware.Context.api).then((updatedUsp) => {
this.usp = updatedUsp;
this.isLoading = false;
});
}).catch(() => {
this.createNotificationError({
title: this.$tc('global.default.error'),
message: this.$tc('s7-usp.detail.notificationErrorMessage'),
});
this.isLoading = false;
});
},
You also need to set Required flag to TranslationsAssociationField also.
(new TranslationsAssociationField(UspTranslationDefinition::class, 'suiteseven_usp_id'))->addFlags(new Required()),

How to use graphql dataloader loadMany function properly in nestjs?

I want to use dataloader loadMany function in nestjs. Can any help me to use it properly-
dataloader.service.ts-
#Injectable()
export class DataloaderService {
constructor(private readonly categoryService: CategoryService) { }
createLoaders(): IDataloaders {
const subCategoryLoader = new DataLoader<ObjectId, Subcategory>(
async (keys: readonly ObjectId[]) =>
this.categoryService.findSubCategoryByBatch(keys as ObjectId[])
);
return {
subCategoryLoader
};
}
}
Then I category service(findSubCategoryByBatch)-
async findSubCategoryByBatch(Ids: ObjectId[]): Promise<(Subcategory | Error)[]> {
const categories = await this.subCategoryModel.find({ _id: { $in: Ids } });
const mappedResults = Ids.map(
(id) =>
categories.find((result) => result.id === id) ||
new Error(`Could not load owner ${id}`),
);
return mappedResults;
}
Then I call it -
#ResolveField('subCategory', () => [Subcategory])
getSubCategory(
#Parent() category: Category,
#Context() { loaders }: IGraphQLContext
) {
return loaders.subCategoryLoader.loadMany(category.subCategory)
}
Notice: I use loadMany function because subCategory is a array IDs.
But I am getting error. Here How to write function for loadMany function. Please help me. I need it. Please help me. please help me.

Wait until API fully loads before running next function -- async/await -- will this work?

I am a beginner with Javascript with a bit of knowledge of VueJs. I have an array called tickets. I also have a data api returning two different data objects (tickets and user profiles).
The tickets have user ids and the user profiles has the ids with names.
I needed to create a method that looks at both of that data, loops through it, and assigns the full name of the user to the view.
I was having an issue where my tickets object were not finished loading and it was sometimes causing an error like firstname is undefined. So, i thought I'd try and write an async/await approach to wait until the tickets have fully loaded.
Although my code works, it just doesn't "feel right" and I am not sure how reliable it will be once the application gets larger.
Can I get another set of eyes as to confirmation that my current approach is OK? Thanks!
data() {
return {
isBusy: true,
tickets: [],
userProfiles: [],
}
},
created() {
this.getUserProfiles()
this.getTickets()
},
methods: {
getUserProfiles: function() {
ApiService.getUserProfiles().then(response => {
this.userProfiles = response.data
})
},
getTickets() {
ApiService.getTickets().then(response => {
this.tickets = response.data
this.assignNames(this.tickets)
this.isBusy = false
})
},
// lets wait until the issues are loaded before showing names;
async assignNames() {
let tickets = await this.tickets
var i
for (i = 0; i < this.tickets.length; i++) {
if (tickets[i].assigned_to !== null) {
const result = this.userProfiles.filter(profile => {
return profile.uid == tickets[i].assigned_to
})
tickets[i].assigned_to = result[0].firstname + ' ' + result[0].lastname
}
}
}
}
}
</script>
There are several ways you could do this. Here is the one I prefer without async/await:
created() {
this.load();
},
methods: {
getUserProfiles: function() {
return ApiService.getUserProfiles().then(response => {
this.userProfiles = response.data
})
},
getTickets() {
return ApiService.getTickets().then(response => {
this.tickets = response.data
})
},
load() {
Promise.all([
this.getUserProfiles(),
this.getTickets()
]).then(data => {
this.assignNames();
this.isBusy = false;
});
},
assignNames(){
const tickets = this.tickets;
for (let i = 0; i < this.tickets.length; i++) {
if (tickets[i].assigned_to !== null) {
const result = this.userProfiles.filter(profile => {
return profile.uid == tickets[i].assigned_to
})
tickets[i].assigned_to = result[0].firstname + ' ' + result[0].lastname
}
}
}
}

How to avoid duplicate entries in IBM JSONStore

WL.JSONStore.get(collectionName).change(data, options) method does not seem to work for duplicate values. I get duplicate values entered whenever data is loaded through the adapter. Below is the code that I have used to avoid duplicate entries.
init(){
console.log('JSONStore init function callled');
let collections = {
activities: {
searchField: {serialKey: 'string'},
adapter: {
name: 'ServiceAdapter',
add: 'pushActivities',
remove: 'removeActivity',
replace: 'replaceActivity',
load: {
procedure: 'getActivities',
params: [],
key: 'rows'
}
}
}
}
WL.JSONStore.init(collections).then((success) => {
console.log('-->JSONStore init success')
}, (failure) => {
console.log('-->JSONStore init failed', failure)
})
}
load() {
let dataRequest = new
WLResourceRequest("/adapters/ServiceAdapter/getActivities",
WLResourceRequest.GET);
dataRequest.send().then(
(response) => {
this.data = response.responseJSON.rows;
this.activityService.put(this.data);
})
}
put(data){
console.log('--> JSONStore put function called');
let collectionName = 'activities';
let options = {
replaceCriteria: ['serialKey'],
addNew: true,
markDirty: false
};
WL.JSONStore.get(collectionName).change(data, options).then((success) => {
console.log('--> JSONStore put success')
}, (failure) => {
console.log('--> JSONStore put failed', failure)
})
}
Adapter Function:
function getActivities() {
var path = 'employees' + '/_all_docs?include_docs=true';
var input = {
method : 'get',
returnedContentType : 'json',
path : path,
};
var response = MFP.Server.invokeHttp(input);
if (!response.rows) {
response.isSuccessful = false;
return response;
} else {
var results = [];
for (var i=0; i < response.rows.length; i++) {
results.push(response.rows[i].doc);
}
return {'rows': results};
}
}
I have even tried by:
searchFields: {serialKey: 'string',serialId: 'string'}
replaceCriteria: ['serialKey','serialId']
But no luck.
NOTE: There is no error in the former one, whereas the later results in an error.
ERROR : PROVISION_TABLE_SEARCH_FIELDS_MISMATCH (I have already tried to destroy the collection and perform the change, as the link suggests.
I have followed the below link:
https://www.youtube.com/watch?v=Ep6w1zXoI-k
I am using the below versions:
mfpdev : 8.0.0-2017102406
Let me know if you need any more details.