I'm trying to show some message through ion-alert after getting data by getTask(taskId).
But seems it shows alert dialogue before data returned, so this.item in message shows undefined.
How can I make sure data returned before showing alert dialogue?
list.page.ts
items: Array<any>;
item: any;
constructor(
public loadingCtrl: LoadingController,
private authService: AuthService,
private router: Router,
private route: ActivatedRoute,
private firebaseService: FirebaseService,
private alertCtrl: AlertController,
) { }
async delete(clickedItem: any) {
let itemId = clickedItem.payload.doc.id;
this.firebaseService.getTask(itemId)
.then(data => {
this.item = data;
}, err => {
console.log(err);
});
const alert = await this.alertCtrl.create({
header: 'Confirm',
// this.item is undefined here
message: 'Do you want to delete ' + this.item.title + '?',
buttons: [
{
text: 'No',
role: 'cancel',
cssClass: 'secondary',
handler: () => {}
},
{
text: 'Yes',
handler: () => {
this.firebaseService.deleteTask(itemId)
.then(
res => {
this.router.navigate(["/list"]);
},
err => console.log(err)
)
}
}
]
});
await alert.present();
}
firebase.service.ts
getTask(taskId){
return new Promise<any>((resolve, reject) => {
this.afAuth.user.subscribe(currentUser => {
if(currentUser){
this.snapshotChangesSubscription = this.afs.doc<any>('people/' + currentUser.uid + '/tasks/' + taskId).valueChanges()
.subscribe(snapshots => {
resolve(snapshots);
}, err => {
reject(err)
})
}
})
});
}
Try it:
async delete(clickedItem: any) {
let itemId = await clickedItem.payload.doc.id;
await this.firebaseService.getTask(itemId)
.then(data => {
this.item = data;
}, err => {
console.log(err);
});
const alert = await this.alertCtrl.create({
header: 'Confirm',
// this.item is undefined here
message: 'Do you want to delete ' + this.item.title + '?',
buttons: [
{
text: 'No',
role: 'cancel',
cssClass: 'secondary',
handler: () => {}
},
{
text: 'Yes',
handler: () => {
this.firebaseService.deleteTask(itemId)
.then(
res => {
this.router.navigate(["/list"]);
},
err => console.log(err)
)
}
}
]
});
await alert.present();
}
Or You can also try It
async delete(clickedItem: any) {
let itemId = await clickedItem.payload.doc.id;
this.firebaseService.getTask(itemId)
.then(async data => {
this.item = data;
const alert = await this.alertCtrl.create({
header: 'Confirm',
// this.item is undefined here
message: 'Do you want to delete ' + this.item.title + '?',
buttons: [
{
text: 'No',
role: 'cancel',
cssClass: 'secondary',
handler: () => {}
},
{
text: 'Yes',
handler: () => {
this.firebaseService.deleteTask(itemId)
.then(
res => {
this.router.navigate(["/list"]);
},
err => console.log(err)
)
}
}
]
});
await alert.present();
}, err => {
console.log(err);
});
}
Related
react-native-push-notification's configure method is not return data. Data is coming null .Here is my code
React.useEffect(() => {
PushNotification.configure({
onNotification(notification) {
if (notification.userInteraction) {
console.log(notification);
console.log('hi');
}
var nottype = notification.data.actionId;
var notid = notification.data.id;
console.log(notid);
AsyncStorage.setItem('actionId', nottype);
AsyncStorage.setItem('orderId', notid);
},
});
}, []);
you are using react-native-push-notification this library is not the best to handle notification. instead you can use #notifee/react-native to configure this for notification. this is very easy to use and do not need native code configuration.
to create a group or single channel
// Create a group
await notifee.createChannelGroup({
id: 'personal',
name: 'Personal',
});
// Assign the group to the channel
await notifee.createChannel({
id: 'comments',
name: 'New Comments',
groupId: 'personal',
});
here is a sample
import notifee, {
AndroidBadgeIconType,
EventType,
TriggerType,
} from '#notifee/react-native';
const onDisplayNotification = async (item, distance, message) => {
try {
await notifee.requestPermission();
const channelId = await notifee.createChannel({
id: 'default',
name: 'Default Channel',
});
await notifee.displayNotification({
title: `You are getting ${message} ${
message == 'Close' ? 'to' : 'from'
} ${item.name}`,
body: `You are ${distance} M away form ${item.name}`,
android: {
channelId,
actions: [
{
title: 'Close',
pressAction: {
id: 'stop',
},
},
],
smallIcon: 'ic_launcher',
pressAction: {
id: 'default',
},
},
});
} catch (e) {
console.error(e, 'ERRORORORORORORO');
}
};
here is the event with which you can interreact with them .
useEffect(() => {
return notifee.onForegroundEvent(({ type, detail }) => {
switch (type) {
case EventType.DISMISSED:
console.log('User dismissed notification', detail.notification);
break;
case EventType.PRESS:
console.log('User pressed notification', detail.notification);
break;
}
});
}, []);
I have the following controller action
[HttpPost]
[Route("api/Tenant/SetTenantActive")]
public async Task<IHttpActionResult> SetTenantActive(string tenantid)
{
var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
var allTenants = await tenantStore.Query().Where(x => x.TenantDomainUrl != null).ToListAsync();
foreach(Tenant ten in allTenants)
{
ten.Active = false;
await tenantStore.UpdateAsync(ten);
}
var tenant = await tenantStore.Query().FirstOrDefaultAsync(x => x.Id == tenantid);
if (tenant == null)
{
return NotFound();
}
tenant.Active = true;
var result = await tenantStore.UpdateAsync(tenant);
return Ok(result);
}
And my react code:
import React, { Component } from 'react';
import { Table, Radio} from 'antd';
import { adalApiFetch } from '../../adalConfig';
import Notification from '../../components/notification';
class ListTenants extends Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
fetchData = () => {
adalApiFetch(fetch, "/Tenant", {})
.then(response => response.json())
.then(responseJson => {
if (!this.isCancelled) {
const results= responseJson.map(row => ({
key: row.ClientId,
ClientId: row.ClientId,
ClientSecret: row.ClientSecret,
Id: row.Id,
SiteCollectionTestUrl: row.SiteCollectionTestUrl,
TenantDomainUrl: row.TenantDomainUrl
}))
this.setState({ data: results });
}
})
.catch(error => {
console.error(error);
});
};
componentDidMount(){
this.fetchData();
}
render() {
const columns = [
{
title: 'Client Id',
dataIndex: 'ClientId',
key: 'ClientId'
},
{
title: 'Site Collection TestUrl',
dataIndex: 'SiteCollectionTestUrl',
key: 'SiteCollectionTestUrl',
},
{
title: 'Tenant DomainUrl',
dataIndex: 'TenantDomainUrl',
key: 'TenantDomainUrl',
}
];
// rowSelection object indicates the need for row selection
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
if(selectedRows[0].key != undefined){
console.log(selectedRows[0].key);
const options = {
method: 'post',
body: {tenantid:selectedRows[0].key},
};
adalApiFetch(fetch, "/Tenant/SetTenantActive", options)
.then(response =>{
if(response.status === 200){
Notification(
'success',
'Tenant created',
''
);
}else{
throw "error";
}
})
.catch(error => {
Notification(
'error',
'Tenant not created',
error
);
console.error(error);
});
}
},
getCheckboxProps: record => ({
type: Radio
}),
};
return (
<Table rowSelection={rowSelection} columns={columns} dataSource={this.state.data} />
);
}
}
export default ListTenants;
focus only on the onchange event,
And the screenshot:
And it looks like the request gets to the webapi (I attached the debugger)
Update:
Basically If I dont put FromBody I need to send the parameter via querystring.
However if I put from Body and I send the parameter in the body, its received null on the webapi
Add [FromBody] before your input parameter in your action method like this:
public async Task<IHttpActionResult> SetTenantActive([FromBody] string tenantid)
Then, convert your selected row key into string
const options = {
method: 'post',
body: { tenantid : selectedRows[0].key.toString() }
};
Action "type": undefined, is what I keep getting returned when I try to test a redux action with fetch-mock. Any suggestion on how to resolve this issue? Could it be a bug in fetch-mock?
Expected value to equal:
[{"type": undefined}, {"result": {"hello": "world"}, "type": undefined}]
Received:
[{"type": "DASHBOARD_RESULT_LOADING"}, {"result": {"hello": "world"}, "type": "DASHBOARD_RESULT_READY"}]
dashboardActions.js
function resultReady(json) {
return {
type: DASHBOARD_RESULT_READY,
result: camelizeKeys(json)
};
}
export function requestPredict(params) {
let url = `${process.env.API_URL}/predict/`;
const requestParams = {
method: 'post',
credentials: 'include'
};
return async (dispatch) => {
return fetch(url, requestParams)
.then(response => {
if (response.status === 200) {
return response.json();
} else {
throw Error(response.statusText);
}
})
.then(data => dispatch(resultReady(data)));
};
}
dashboardActions.test.js
const mockData = {
"hello": "world"
}
describe('action creators', () => {
afterEach(() => {
fetchMock.reset()
})
it('should create DASHBOARD_RESULT_LOADING', () => {
fetchMock.post('*', {"hello":"world"} );
const expectedActions = [
{ type: actions.DASHBOARD_RESULT_LOADING },
{ type: actions.DASHBOARD_RESULT_READY, result: mockData }
]
const store = mockStore({ result: {}})
return store.dispatch(actions.requestPredict())
.then((data) => {
expect(store.getActions()).toEqual(expectedActions)
})
})
})
You're receiving types "DASHBOARD_RESULT_LOADING" and "DASHBOARD_RESULT_READY", which seems to be the intended behaviour. You're expecting actions.DASHBOARD_RESULT_LOADING and actions.DASHBOARD_RESULT_READY, neither of which seems to be defined with any value.
Either define actions.DASHBOARD_RESULT_LOADING and actions.DASHBOARD_RESULT_READY:
actions.DASHBOARD_RESULT_LOADING = 'DASHBOARD_RESULT_LOADING'
actions.DASHBOARD_RESULT_READY = 'DASHBOARD_RESULT_READY'
or replace them with your expected types:
const expectedActions = [
{
type: 'DASHBOARD_RESULT_LOADING'
},
{
type: 'DASHBOARD_RESULT_READY',
result: mockData
}
]
I have this action in my vuex store:
loadExercises ({commit}) {
commit('setLoading', true)
const db = firebase.firestore()
db.collection('exercises').get()
.then(querySnapshot => {
const exercises = []
querySnapshot.forEach((doc) => {
exercises.push({
title: doc.data().title,
language: doc.data().language,
translated: doc.data().translated,
lastOpen: doc.data().lastOpen,
dueDate: doc.data().dueDate,
uid: doc.data().uid,
userId: doc.data().userId,
words: [{ word: '', uid: '', translation: '' }]
})
db.collection('exercises').doc(doc.data().uid).collection('words').get()
.then(words => {
const wordsArray = []
words.forEach(word => {
wordsArray.push(word.data())
})
let exercise = this.getters.loadedExercise(doc.data().uid)
exercise.words = wordsArray
})
.catch(error => {
commit('setLoading', false)
console.log(error)
})
})
commit('setLoading', false)
commit('setLoadedExercises', exercises)
})
.catch(error => {
commit('setLoading', false)
console.log(error)
})
}
It is supposed to fetch exercises from a firebase cloudstore db. It works on some routes but not all.
When using these two getters it works:
loadedExercises (state) {
return state.loadedExercises
},
loadedExercise (state) {
return (exerciseId) => {
return state.loadedExercises.find(exercise => {
return exercise.uid === exerciseId
})
}
}
But when I use these getters:
upcomingExercises (state, getters) {
return getters.loadedExercises.filter(exercise => {
return exercise.dueDate > 0
})
},
latestExercises (state, getters) {
return getters.loadedExercises.splice(0, 5)
},
it does not work I just get "TypeError: Cannot set property 'words' of undefined". What is it that I do wrong?
It looks to me like you aren't returning the values back to the function.
Try replacing
db.collection('exercises').get()
with
return db.collection('exercises').get()
and
db.collection('exercises').doc(doc.data().uid).collection('words').get()
with
return db.collection('exercises').doc(doc.data().uid).collection('words').get()
i am actually working on a mobile app in ionic v3 with angular5
The goal is to be able to take a picture or choose from existing ones and then upload it to the server. The first part is done, but i am struggling with the upload.
The api needs multipart/form-data which must consist of two requests. First with text part and second is the image.
Is there any solution for this?
This is what I have done for similar requirement
takePhoto() {
this.camera.getPicture({
quality: 100,
destinationType: this.camera.DestinationType.FILE_URI,
sourceType: this.camera.PictureSourceType.CAMERA,
encodingType: this.camera.EncodingType.PNG,
saveToPhotoAlbum: true
}).then(imageData => {
this.myPhoto = imageData;
this.uploadPhoto(imageData);
}, error => {
this.functions.showAlert("Error", JSON.stringify(error));
});
}
selectPhoto(): void {
this.camera.getPicture({
sourceType: this.camera.PictureSourceType.PHOTOLIBRARY,
destinationType: this.camera.DestinationType.FILE_URI,
quality: 100,
encodingType: this.camera.EncodingType.PNG,
}).then(imageData => {
this.myPhoto = imageData;
this.uploadPhoto(imageData);
}, error => {
this.functions.showAlert("Error", JSON.stringify(error));
});
}
private uploadPhoto(imageFileUri: any): void {
this.file.resolveLocalFilesystemUrl(imageFileUri)
.then(entry => (<FileEntry>entry).file(file => this.readFile(file)))
.catch(err => console.log(err));
}
private readFile(file: any) {
const reader = new FileReader();
reader.onloadend = () => {
const formData = new FormData();
const imgBlob = new Blob([reader.result], { type: file.type });
formData.append('evaluationID', this.currentEvaluation.evaluationId);
formData.append('standardID', this.currentEvaluation.id);
formData.append('score', this.currentEvaluation.score);
formData.append('comment', this.currentEvaluation.comment);
formData.append('file', imgBlob, file.name);
this.saveStandard(formData);
};
reader.readAsArrayBuffer(file);
}
And here is code for provider
saveStandard(receivedStandardInfo:any){
return new Promise((resolve, reject) => {
this.http.post(apiSaveStandard,receivedStandardInfo)
.subscribe(res => {
resolve(res);
}, (err) => {
console.log(err);
reject(err);
});
}).catch(error => { console.log('caught', error.message); });
}