I'm trying to add a popup that will be shown on a page when the user starts to populate data in the form and then he decided to go somewhere else in the app.
This popup will show this message: 'Do you want to leave this page and save your changes?'
three buttons are available: Stay, Leave and Save before leaving.
I'm new to ionic logic and I couldn't figure out how to do this.
I started by adding a button in the page that shows the popup (Still don't know how to trigger the event when the user clicks on any link of the sidebar for example). when the user clicks on that button the popup is shown with the three buttons.
The problem is that I don't know how to implement the handlers of these buttons.
This is what I have in the ts file :
leaveOrStayModal() {
let e = event || window.event;
e.stopPropagation();
this.alertMixin.presentAlert(
'Do you want to leave this site?\n',
"You haven't saved your changes!",
'Stay',
'Leave',
'Save',
null,
() => {
console.log('leave handler')
// this.navCtrl.push() Here I don't know how to get the exact link clicked from the sidebar ? to go to
},
() => {
console.log('Save handler')
//here I want to save the form ?
}
)
}
the popup code:
presentAlert(title: string, message: string, btnOneText: string, btnTowText: string, btnThreeText: string,
btnOneHandler?: () => void, btnTowHandler?: () => void, btnThreeHandler?: () => void,
present: boolean = true) {
let confirm = this.alertCtrl.create({
title: title,
message: message,
buttons: [
{
text: btnOneText,
handler: () => {
if (btnOneHandler) {
btnOneHandler();
}
}
},
{
text: btnTowText,
handler: () => {
if (btnTowHandler) {
btnTowHandler();
}
}
},
{
text: btnThreeText,
handler: () => {
if (btnThreeHandler) {
btnThreeHandler();
}
}
}
]
});
if (present) {
confirm.present().then();
}
return confirm;
}
And this is the button that shows the popup (to be removed )
<button ion-button icon-left item-right type="button" (click)="leaveOrStayModal()"> Click to show modal </button>
You should leverage life cycle hook ionViewCanLeave for that. Some basic documentation here: https://ionicframework.com/docs/api/navigation/NavController/
For your context I just drafted the way I would do it (its a bit dirty):
userCanLeave = false;
ionViewCanLeave() {
// here you can use other vars to see if there are reasons we want to keep user in this page:
if (!this.userCanLeave) {
return new Promise((resolve, reject) => {
let alert = this.alertCtrl.create({
title: 'Are you sure?',
message: 'The form data may be lost',
buttons: [
{
text: 'Stay',
role: 'cancel',
handler: () => {
console.log('User stayed');
this.userCanLeave = false;
reject();
}
},
{
text: 'Leave',
handler: () => {
console.log('User leaves');
this.userCanLeave = true;
resolve();
}
},
{
text: 'Save',
handler: () => {
console.log('User saved data');
// do saving logic
this.userCanLeave = true;
resolve();
}
}
]
});
alert.present();
});
} else { return true }
}
userCanLeave - here is just example of a var that defines if the page has the state where we would not want a user to leave "freely".
then we use promise to ensure that user can not leave without answering dialogue options, we wait for their answers to define whether life cycle hook gets true/false flag to proceed.
Please note also that this life cycle hook only "kicks in" when a view (page) gets off the stack (pops) if you would push in a new view - it won't guard that. But in this case new pushed in page won't destroy user's data in the form anyway and user can safely return to it once you dismiss that newly pushed in page.
Hope this helps.
Related
ANSWER GetItemURL is only used for keyboard interactions. It is not used for the mouse handling. Mouse handling is done by the rendered HTML (from the template). The simplest approach is to use a a HREF In your template, or an OnClick handler that takes you to another page!
—————————-
I've copied the default autocomplete code for static sources, the completion and filters work, and getItemURL is called correctly, however on click the URL does not change.
I've created a sandbox you can see ithere.
Default code:
const { autocomplete } = window["#algolia/autocomplete-js"];
const autocomplete_id = "#autocomplete-search-box";
function CreateAutoComplete(appid, search_api_key, index_name) {
console.log("CreateAutoComplete Called");
autocomplete({
container: autocomplete_id,
placeholder: "Type T to get completions",
getSources() {
return [
{
sourceId: "links",
getItems({ query }) {
const items = [
{ label: "Twitter", url: "https://twitter.com" },
{ label: "GitHub", url: "https://github.com" }
];
return items.filter(({ label }) =>
label.toLowerCase().includes(query.toLowerCase())
);
},
getItemUrl({ item }) {
console.log("GetItemURL", item);
console.log("returning", item.url);
return item.url;
},
templates: {
item({ item }) {
return item.label;
}
}
}
];
}
});
}
Remember that getItemUrl() is expecting a keyboard interaction (navigate via arrows and click enter) to navigate over to the result URL, not a click.
This is working in your codesandbox, although the redirect is being blocked by Twitter/Github.
my code is :
function autocomplet() {
var min_length = 0; // min caracters to display the autocomplete
var keyword = $('#country_id').val();
if (keyword.length >= min_length) {
$.ajax({
url: 'ajaxname.php',
type: 'POST',
data: {keyword:keyword},
success:function(data){
$('#country_list_id').show();
$('#country_list_id').html(data);
}
});
} else {
$('#country_list_id').hide();
}
}
function set_item(item) {
// change input value
$('#country_id').val(item);
// hide proposition list
$('#country_list_id').hide();
}
and i wana hide ul (country_list_id) when user click on anywhere ?
and im not good in ajax :(
so any one can edit this code
Assuming you just want to hide the id when the user click basically anything.
Then here.
$(document).on("click", () => {
$('#country_list_id').hide();
})
I'm new in NativeScript, and I'm playing with maps, using Mapbox.
I want add markers, programmatically from a function when tap a buttom, to map.
XML
` <Button text="GET" tap="getRequest" /> <<<-- BUTTON!
<ContentView>
<map:MapboxView
accessToken= token
mapStyle="streets"
zoomLevel="13"
showUserLocation="false"
disableRotation= "true"
disableTilt="false"
mapReady="onMapReady">
</map:MapboxView>
</ContentView>`
JS
`function onMapReady(args) {
args.map.addMarkers([
{
id: 1,
lat: -35.30505050,
lng: -47.56263254,
title: 'Company 1', // no popup unless set
subtitle: 'Subt 1',
iconPath: 'markers/green_pin_marker.png',
onTap: function () { console.log("'Nice location' marker tapped"); },
onCalloutTap: function () {
console.log("'Nice location' marker callout tapped");
console.log(lati + long);
}
}
]).then(
function (result) {
console.log("Mapbox addMarkers done");
},
function (error) {
console.log("mapbox addMarkers error: " + error);
})
}
exports.onMapReady = onMapReady;`
That code works fine, the marker ID 1 appears on map.
My question is: how can add others markers from a function that responde to tap button:
exports.getRequest = function () {
console.log("BUTTON TAPPED!");
args.map.addMarkers([
{
id: 2,
lat: -35.30586500,
lng: -47.56218500,
title: 'Company 2', // no popup unless set
subtitle: 'Subt 2',
iconPath: 'markers/green_pin_marker.png',
onTap: function () { console.log(" marker tapped"); },
onCalloutTap: function () {
console.log("marker callout tapped");
console.log(lati + long);
}
}
]).then(
function (result) {
console.log("Mapbox addMarkers done");
},
function (error) {
console.log("mapbox addMarkers error: " + error);
})
}
When tap button, console show message BUTTON TAPPED!, but no new mapker ID 2 on map.
I'm doing bad or forgeting something?
Well, it's in the readme of the plugin repo: https://github.com/EddyVerbruggen/nativescript-mapbox/tree/26019957e4e3af3e737d7a44c845f5d5b1bfb808#addmarkers
So here's a JavaScript example, but that repo also has a TypeScript-based demo app with an 'add markers' button that you can check out:
var mapbox = require("nativescript-mapbox");
var onTap = function(marker) {
console.log("Marker tapped with title: '" + marker.title + "'");
};
var onCalloutTap = function(marker) {
alert("Marker callout tapped with title: '" + marker.title + "'");
};
mapbox.addMarkers([
{
id: 2, // can be user in 'removeMarkers()'
lat: 52.3602160, // mandatory
lng: 4.8891680, // mandatory
title: 'One-line title here', // no popup unless set
subtitle: 'Infamous subtitle!',
// icon: 'res://cool_marker', // preferred way, otherwise use:
icon: 'http(s)://website/coolimage.png', // from the internet (see the note at the bottom of this readme), or:
iconPath: 'res/markers/home_marker.png',
selected: true, // makes the callout show immediately when the marker is added (note: only 1 marker can be selected at a time)
onTap: onTap,
onCalloutTap: onCalloutTap
},
{
// more markers..
}
])
I also cannot use Mapbox as a const/var... or do anything programmatically. I get undefined is not a function, yet Mapbox to log yields the module and its objects. I can see the appropriate functions under prototype:Mapbox etc.
Only declaring the map in XML and utilizing the MapOnReady function works for me.
Update:
I stumbled upon this thread from {N} discourse that helped me understand:
https://discourse.nativescript.org/t/adding-mapbox-to-layout-container/4679/11
Basically the programatic way of building the map still does not allow interaction with the map after it has been rendered. You just declare all the map options as shown in the git example and then still use onMapReady as your function to add markers, polylines etc... you can still setup map listeners of course.
I have an issue where I have a resource with a new route. When I transition to that new route I create a new object. On the form I have button to cancel, which removes that object. However, if I click a link on my navigation, say going back to the resource index, that object is there with whatever I put in the form. What's the best way of managing creating objects then moving away from the form?
My routes:
App.Router.map(function() {
this.resource('recipes', function() {
this.route('new');
this.route('show', { path: '/:recipe_id' });
});
this.resource('styles');
});
App.RecipesNewRoute = Ember.Route.extend({
model: function() {
return App.Recipe.createRecord({
title: '',
description: '',
instructions: ''
});
},
setupController: function(controller, model) {
controller.set('styles', App.Style.find());
controller.set('content', model);
}
});
My controller for the new route:
App.RecipesNewController = Ember.ObjectController.extend({
create: function() {
this.content.validate()
if(this.content.get('isValid')) {
this.transitionToRoute('recipes.show', this.content);
}
},
cancel: function() {
this.content.deleteRecord();
this.transitionToRoute('recipes.index');
},
buttonTitle: 'Add Recipe'
});
I'm using version 1.0.0.rc.1
Thanks!
Any code that you place in the deactivate method of your route will get executed every time you leave that route. The following code will delete the new model if the user hasn't explicitly saved it.
App.RecipesNewRoute = Ember.Route.extend({
// ...
deactivate: function() {
var controller = this.controllerFor('recipes.new');
var content = controller.get('content');
if (content && content.get('isNew') && !content.get('isSaving'))
content.deleteRecord();
},
// ...
});
As an added bonus, you now don't need to explicitly delete the record when the user presses the cancel button.
I am using form editing but I only want the ADD form to appear if the results from dataURL are correct. I can hide it, but I really don't want it at all on condition. Plus, the hide() only works after the alert is cleared
$("#schedule").jqGrid('editGridRow', "new", {
url: './ar_schedule_update.cgi?',
editData: {visitor:visitor},
beforeInitData: function() {
$('#schedule').setColProp('archiveid',{editable: true,hidden:false, edittype: 'select',
editoptions: {dataUrl: './ar_archiveid_edit_options.cgi?system=' + selected_system,
buildSelect: function(data) {
if (data.match(/^ERROR/)) {
$('#editmodschedule').hide(); //Makes it disappear ok after alert cleared
alert(data);
return false;
}
return data;
}
}
});
},
beforeShowForm: function(formid) {
//NEED TO EVALUATE CONDITION HERE? AND BAIL IF ERROR
},
onClose: function() {...............
Thanks in advance,
Mike