In NativeScript-Vue the SearchBar widget seems to override the back button in Android. The desired behavior is for the back button to close the keyboard and then, if pressed once more, navigate back to the page the user was on before. What happens instead is that the keyboard closes and then subsequent back button presses do nothing. This only happens once the SearchBar has focus.
I've tried registering a listener
mounted: function(){
if(application.android){
application.android.on(application.AndroidApplication.activityBackPressedEvent, this.backEvent);
}
}
That approach worked on other pages but it seems to be completely ignored once the searchBar has focus. Is there a way to capture the back button press event from the searchbar?
Here is the vue template:
<template>
<Page class="page">
<ActionBar title="Home" class="action-bar" />
<ScrollView>
<StackLayout class="home-panel">
<SearchBar id="mySearchBar" #loaded="onLoadedEvent" hint="Search hint" v-model="searchPhrase" #submit="onSearchSubmit" />
<ListView class="list-group" for="country in filteredList" #itemTap="onItemTap" style="height:1250px">
<v-template>
<GridLayout columns="*, 2*" rows="auto, auto" class="list-group-item">
<Image col="0" rowSpan="2" :src="country.imageSrc" />
<Label col="1" colSpan="2" row="0" :text="country.name" class="list-group-item-heading" />
<label col="1" colSpan="2" row="1" :text="country.description" />
</GridLayout>
</v-template>
</ListView>
</StackLayout>
</ScrollView>
</Page>
inside the script tag I have the appropriate imports and then the following inside export default:
methods: {
onLoadedEvent(args){
if(application.android){
args.object.android.clearFocus();
}
},
onItemTap: function (args) {
console.log('Item with index: ' + this.countries[args.index].name + ' tapped');
console.log("Value of searchPhrase: " + this.searchPhrase);
},
onSearchSubmit(args) {
let searchBar = args.object;
console.log("You are searching for " + searchBar.text);
},
onClearEvent(args){
let searchBar = args.object;
}
},
computed: {
filteredList() {
return this.countries.filter(country => {
return country.name.toLowerCase().includes(this.searchPhrase.toLowerCase())
})
}
},
data () {
return {
countries: [
{ name: "Australia", description: "Snakes and stuff", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/au.png" },
{ name: "Belgium", description: "Great Waffles", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/be.png" },
{ name: "Bulgaria", description: "No Clue. Maybe Dracula?", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/bg.png" },
{ name: "Canada", description: "Maple Syrup", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/ca.png" },
{ name: "Switzerland", description: "Chocolate & Watches", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/ch.png" },
{ name: "China", description: "Socialism", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/cn.png" },
{ name: "Czech Republic", description: "Checkers?", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/cz.png" },
{ name: "Germany", description: "AHH, Motherland!", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/de.png" },
{ name: "Spain", description: "Bulls!", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/es.png" },
{ name: "Ethiopia", description: "Hungry", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/et.png" },
{ name: "Croatia", description: "Crows?", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/hr.png" },
{ name: "Hungary", description: "Hung Gary", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/hu.png" },
{ name: "Italy", description: "Meatballs", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/it.png" },
{ name: "Jamaica", description: "Ganja", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/jm.png" },
{ name: "Romania", description: "Not Romans", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/ro.png" },
{ name: "Russia", description: "Putin 4 Life", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/ru.png" },
{ name: "United States", description: "Fat People", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/us.png" },
],
searchPhrase: ""
};
}
Related
I am using b-table (Bootstrap-vue) with API Laravel.
This is the vue code:
<TableCli
:items="items"
:fields="fields"
:rows="rows"
:perPage="perPage">
</TableCli>
.
data: function () {
return {
mode: "save",
item: {},
items: [],
paises: [{}],
checked: 1,
page: 1,
perPage: 10,
fields: [
{ key: "id", label: "Código", sortable: true },
{ key: "name", label: "Name", sortable: true },
{ key: "tva", label: "TVA", sortable: true },
{ key: "country_id", label: "Country", sortable: true},
{ key: "cp", label: "CP", sortable: true },
{ key: "city", label: "City", sortable: true },
{ key: "address", label: "Address", sortable: true },
{
key: "status",
label: "Status",
sortable: true,
formatter: (value) => (value ? "Yes" : "No"),
},
{ key: "actions", label: "Actions" }
],
};
Methods:
methods: {
loadCli() {
const url = `${baseApiUrl}/api/cli`;
axios.get(url).then((res) => {
this.items = res.data;
});
},
loadCountrys() {
const url = `${baseApiUrl}/api/country`;
axios.get(url).then(res => {
this.country = res.data
})
},
My table returns the country id, how do I return the country name?
Another question, how do I add an action button in the Actions column?
The button to edit and delete.
I think this snippet answers your questions. The main idea is using slot for b-table.
new Vue({
el: '#app',
data() {
return {
table_fields: [
{
key: "title",
label: "Title"
},
{
key: "user",
label: "User"
},
{
key: "id",
label: "Detail Button"
}
],
page_contents: [
{
id: "title-id-1",
title: "title 1",
user: {
id: "user-id-1",
name: "name 1",
},
}
]
}
},
methods: {
do_sth(id) {
console.log(id)
}
}
})
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap#4.5.3/dist/css/bootstrap.min.css" />
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.min.js"></script>
<div id="app">
<b-table-lite striped small hover :items="page_contents" :fields="table_fields">
<template #cell(id)="data">
<b-button size="sm" #click='do_sth(data.value)'>Detail Button</b-button>
</template>
<template #cell(user)="data">
<span> {{ data.value.id }} </span>
<span> || </span>
<span> {{ data.value.name }} </span>
</template>
</b-table-lite>
</div>
I need to send object to the server:
{
"id": "null",
"indexNumber": "1454",
"indexYear": "2021",
"firstName": "John",
"lastName": "Doe",
"email": "john#doe.com",
"address": "John Doe Street 1231",
"city": {
"postalCode": 10000,
"name": "New York"
} ,
"currentYearOfStudy": 1
}
when I use to test it from postman everything is fine, but when I try to send object "student" from frontend i got this error message "Cannot read property 'postalCode' of undefined:
Where do I need to define this property, or where to define object city, how to do this?
inserStudent() {
StudentService.insertStudent({
indexNumber: this.indexNumber,
indexYear: this.indexYear,
firstName: this.firstName,
lastName: this.lastName,
email: this.email,
address: this.address,
postalCode: this.city.postalCode,
name: this.city.name,
currentYearOfStudy: this.currentYearOfStudy
})
.then((response) => {
console.log("Student inserted!" + response);
addMessage({
message: "Student inserted!",
type: "success",
title: "STUDENT",
});
})
.catch((error) => {
addMessage({
message: "Insert was not successful:" + error,
type: "danger",
title: "Insert student",
});
});
}
Sorry I'm new to vue...
<template>
<div class="form-container m-4 col-6 col-md-8 col-sm-10 mx-auto" display-inline-block>
<h3 v-if="actionType === 'new'">New Student</h3>
<h3 v-else>Edit Student</h3>
<MyInputComponent
name="indexNumber"
label="Index Number"
v-model="indexNumber"
:vcomp="v$.indexNumber"
></MyInputComponent>
<MyInputComponent
name="indexYear"
label="Index Year"
v-model="indexYear"
:vcomp="v$.indexYear" >
</MyInputComponent>
<MyInputComponent
name="firstName"
label="First Name"
v-model="firstName"
:vcomp="v$.firstName"
>
</MyInputComponent>
<MyInputComponent
name="lastName"
label="Last Name"
v-model="lastName"
:vcomp="v$.lastName"
>
</MyInputComponent>
<MyInputComponent
name="email"
label="Email"
v-model="email"
:vcomp="v$.email"
>
</MyInputComponent>
<MyInputComponent
name="address"
label="Address"
v-model="address"
:vcomp="v$.address"
>
</MyInputComponent>
<MyInputComponent
name="postalCode"
label="Postal Code"
v-model="postalCode"
:vcomp="v$.postalCode"
>
</MyInputComponent>
<MyInputComponent
name="name"
label="City Name"
v-model="name"
:vcomp="v$.name"
>
</MyInputComponent>
<MyInputComponent
name="currentYearOfStudy"
label="Curent Year Of Study"
v-model="currentYearOfStudy"
:vcomp="v$.currentYearOfStudy"
>
</MyInputComponent>
<div class="d-flex flex-row-reverse">
<button class="btn btn-outline-primary" #click="saveStudent">Save</button>
</div>
</div>
</template>
<script>
import useValidate from "#vuelidate/core";
import {
required,
minLength,
maxLength,
email,
maxValue,
minValue,
} from "#vuelidate/validators";
import MyInputComponent from "#/components/inputs/MyInputControl.vue";
import StudentService from "#/services/StudentService.js";
import { addMessage } from "#/main.js";
export default {
components: { MyInputComponent },
props: {
studentId: {
type: String,
},
actionType: {
type: String,
},
},
created() {
if (this.studentId) {
StudentService.getStudent(this.studentId).then((response) => {
const student = response.data;
this.indexNumber = student.indexNumber;
this.indexYear = student.indexYear;
this.firstName = student.firstName;
this.lastName = student.lastName;
this.email = student.email;
this.address = student.address;
this.postalCode = student.city.postalCode;
this.name = student.city.name;
this.currentYearOfStudy = student.currentYearOfStudy;
});
}
},
data() {
return {
v$: useValidate(),
id:null,
indexNumber: "",
indexYear: "",
firstName: "",
lastName: "",
email: "",
address: "",
postalCode: "",
name: "",
currentYearOfStudy: null,
randomNumber:''
};
},
validations() {
return {
indexNumber: {
required,
minLength: minLength(4),
maxLength: maxLength(4),
},
indexYear: {
required,
minLength: minLength(4),
maxLength: maxLength(4),
},
firstName: {
required,
minLength: minLength(3),
maxLength: maxLength(30),
},
lastName: {
required,
minLength: minLength(3),
maxLength: maxLength(30),
},
email: {
required,
email,
},
address: {
required,
minLength: minLength(3),
},
postalCode:{
required,
minValue: minValue(9999),
maxValue: maxValue(100000),
},
name:{
required,
minLength: minLength(3),
maxLength: maxLength(30)
},
currentYearOfStudy: {
required,
minValue: minValue(1),
maxValue: maxValue(5),
},
};
},
methods: {
saveStudent() {
if (this.actionType && this.actionType === "new") {
this.inserStudent();
} else {
this.updateStudent();
}
},
inserStudent() {
StudentService.insertStudent({
indexNumber: this.indexNumber,
indexYear: this.indexYear,
firstName: this.firstName,
lastName: this.lastName,
email: this.email,
address: this.address,
postalCode: this.city.postalCode,
name: this.city.name,
currentYearOfStudy: this.currentYearOfStudy
})
.then((response) => {
console.log("Student inserted!" + response);
addMessage({
message: "Student inserted!",
type: "success",
title: "STUDENT",
});
})
.catch((error) => {
addMessage({
message: "Insert was not successful:" + error,
type: "danger",
title: "Insert student",
});
});
},
updateStudent() {
StudentService.editStudent({
id: this.studentId,
indexNumber: this.indexNumber,
indexYear: this.indexYear,
firstName: this.firstName,
lastName: this.lastName,
email: this.email,
address: this.address,
postalCode: this.city.postalCode,
name: this.city.name,
currentYearOfStudy: this.currentYearOfStudy,
})
.then((response) => {
console.log("Student inserted" + response);
addMessage({
message: "Student updated",
type: "success",
title: "STUDENT",
});
})
.catch((error) => {
addMessage({
message: "Update was not successful:" + error,
type: "danger",
title: "Update student",
});
});
},
},
};
</script>
You've postalCode and name are defined in data property without nesting them, so you could nest them to a city field when you want to send the request :
StudentService.insertStudent({
indexNumber: this.indexNumber,
indexYear: this.indexYear,
firstName: this.firstName,
lastName: this.lastName,
email: this.email,
address: this.address,
city:{
postalCode: this.postalCode,
name: this.name,
},
currentYearOfStudy: this.currentYearOfStudy
})
I'm building a app with just javascript, no typescript, no angular, no vuejs.
Is it possible to use NativeScript UI with pure javascript ?
I'm trying to use radlistview, and the only code I find is on TypeScript.
If not, then what I'm trying to do is just output a list and tapAction on each item to navigato to single item with the data passed of that item.
Anyone have any idea how to do that?
Yes, it's very possible. In many of the examples you'll have to mentally translate from typescript to javascript. I use javascript projects myself and had to make those translations myself when I was first starting. It can be a little confusing.
Irrespective of TypeScript / Angular / Vue, end of the code is complied to plain JavaScript only. These are just modern frameworks / libraries those help to speed up development & make things easier.
The TypeScript code can be compiled into JavaScript using TypeScript CLI, there are even several sites do this within your browser.
RadListView: ViewModel
var frame = require("tns-core-modules/ui/frame");
var observableModule = require("tns-core-modules/data/observable");
function HomeViewModel() {
var viewModel = observableModule.fromObject({
countries: [
{ name: "Australia", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/au.png" },
{ name: "Belgium", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/be.png" },
{ name: "Bulgaria", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/bg.png" },
{ name: "Canada", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/ca.png" },
{ name: "Switzerland", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/ch.png" },
{ name: "China", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/cn.png" },
{ name: "Czech Republic", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/cz.png" },
{ name: "Germany", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/de.png" },
{ name: "Spain", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/es.png" },
{ name: "Ethiopia", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/et.png" },
{ name: "Croatia", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/hr.png" },
{ name: "Hungary", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/hu.png" },
{ name: "Italy", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/it.png" },
{ name: "Jamaica", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/jm.png" },
{ name: "Romania", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/ro.png" },
{ name: "Russia", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/ru.png" },
{ name: "United States", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/us.png" },
],
onItemTap: function (args) {
var bindingContext = args.view.bindingContext;
console.log(bindingContext.name);
},
});
return viewModel;
}
module.exports = HomeViewModel;
Playground Sample
Is there anyone knows a link which shows an example on how to implement itemSelecting in Nativescript angular RadListViewhttps://docs.nativescript.org/ns-ui-api-reference/classes/radlistview#itemselecting?
Because I can't find any example. Thank you.
HTML
<RadListView class="list-group" [items]="countries" selectionBehavior="Press"
multipleSelection="true" (itemSelecting)="onItemSelecting($event)"
(itemDeselecting)="onItemSelecting($event)">
<ng-template let-country="item">
<FlexboxLayout flexDirection="row" class="list-group-item">
<Image [src]="country.imageSrc" class="thumb img-circle"></Image>
<Label [text]="country.name" class="list-group-item-heading"
verticalAlignment="center" style="width: 60%"></Label>
</FlexboxLayout>
</ng-template>
</RadListView>
TS
import { ListViewEventData } from "nativescript-ui-listview"
import { Component } from "#angular/core";
#Component({
selector: "Home",
moduleId: module.id,
templateUrl: "./home.component.html",
styleUrls: ["./home.component.css"]
})
export class HomeComponent {
countries: { name: string, imageSrc: string }[] = [
{ name: "Australia", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/au.png" },
{ name: "Belgium", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/be.png" },
{ name: "Bulgaria", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/bg.png" },
{ name: "Canada", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/ca.png" },
{ name: "Switzerland", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/ch.png" },
{ name: "China", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/cn.png" },
{ name: "Czech Republic", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/cz.png" },
{ name: "Germany", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/de.png" },
{ name: "Spain", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/es.png" },
{ name: "Ethiopia", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/et.png" },
{ name: "Croatia", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/hr.png" },
{ name: "Hungary", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/hu.png" },
{ name: "Italy", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/it.png" },
{ name: "Jamaica", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/jm.png" },
{ name: "Romania", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/ro.png" },
{ name: "Russia", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/ru.png" },
{ name: "United States", imageSrc: "https://play.nativescript.org/dist/assets/img/flags/us.png" },
];
onItemSelecting(args: ListViewEventData): void {
console.log(args.view.bindingContext.name);
args.returnValue = args.index > 5;
}
}
Note: It seems to be buggy, at least on Android. Second tap fails to fire itemSelecting event and marks the item as selected. A workaround could be found at nativescript-ui-feedback/issues/181
I've created an admin dashboard for administrating members. As an admin I can login in do everything.
I need also to allow these members (regular users) to login, be redirected to their profile page and be able to edit a subset of their properties.
I've searched through the documentation but have been unable to figure how best to accomplish this.
Is there a standard way, and if there is how can do this?
All what you need to manage user permissions on your dashboard is available on the Authorization section of the documentation.
Firstly, at the authentication step, you have to set the current user permission (basically a string of your choices, given by the API and/or stored inside the local storage for example: user, admin, user_X, etc):
if (type === AUTH_GET_PERMISSIONS) {
const { role, id } = params;
return Promise.resolve(`${role}_${id}`);
}
Then, you can check this permission inside your resource declaration:
export const UserEdit = ({ ...props }) =>
<Edit title={<UserTitle />} {...props}>
{permissions =>
<TabbedForm defaultValue={{ role: 'user' }}>
<FormTab label="user.form.summary">
<DisabledInput source="id" />
{permissions === `user_${props.record.id}` &&
<TextInput source="name" validate={required} />
}
</FormTab>
</TabbedForm>}
</Edit>;
And you can also restrict an entire resource to administrators:
<Admin
restClient={restClient}
authClient={authClient}
>
{permissions => [
// Restrict access to the remove view to admin only
<Resource
name="customers"
list={UserList}
edit={UserEdit}
remove={permissions.startsWith('admin') ? UserDelete : null}
/>,
// Only include the categories resource for admin users
permissions.startsWith('admin')
? <Resource name="categories" list={CategoryList} edit={CategoryEdit} />
: null,
]}
</Admin>
You could also try to use my ra-component-factory that tackles those problems in a very elegant way: https://github.com/zifnab87/ra-component-factory it is now listed in contributions of admin-on-rest (https://github.com/marmelab/admin-on-rest/blob/master/docs/Ecosystem.md)
Here is the general skeleton of configuration - it helps you set fields as not visible or read-only, menu-item visibility, action button visibility and even tab arrangement per role and per action.
export default {
props: {
id: {
input: (<TextInput source="id"/>),
field: (<TextField source="id"/>),
},
name: {
input: (<TextInput label="Name" source="name"/>),
field: (<TextField label="Name" source="name"/>),
},
date: {
input: (<DateInput source="date" parse={dateParser} label="Post Date"/>),
field: (<DateField source="date" type="date" label="Post Date"/>),
},
dateGte: { //date Greater than equal
input: (<DateInput source="dateGte" parse={dateParser} label="Date from"/>),
},
dateLte: { // date Less than equal
input: (<DateInput source="dateLte" parse={dateParser} label="Date to"/>),
},
author: {
input: <ReferenceInput label="Author" source="author" reference="authors" allowEmpty>
<SelectInput optionText="name" translate={false}/>
</ReferenceInput>,
field: <ReferenceField label="Author" source="author" reference="authors" sortable={false} linkType={false} allowEmpty={true}>
<ChipField source="name"/>
</ReferenceField>
},
},
role1: {
create: {
props: ["name", "author", "date"],
action: true
},
edit: {
props: ["_id", "name", "author", "date"],
action: true
},
list: {
props: ["id", "name", "author", "date"],
action: true
},
filter: {
props: ["q", "id", "author", "dateGte", "dateLte"],
action: true
},
show: {
props: ["id", "name", "author"],
action: true
},
search: {
action: true
},
delete: {
action: true
},
},
role2: {
create: {
props: [],
action: false
},
edit: {
props: [],
action: false
},
list: {
props: ["id", "name", "author", "date"],
action: false
},
filter: {
props: ["q", "id", "author", "dateGte", "dateLte"],
action: true
},
show: {
props: ["id", "name", "author"],
action: true
},
search: {
action: true
},
delete: {
action: false
},
}
}