How to make an accordion list with RadListView? (Nativescript) - nativescript

I am showing data with RadListView that has categories and subentries (Nativescript Angular, iOS).
I want to have the page load showing only the categories, and if the user clicks on any category, it toggles the entries (showing on click, then hiding on another click).
Is this possible?
I have not seen this successfully accomplished with the current version of pro ui and NS. I have not been able to get it to work myself.
Further details about other approaches are here.
There is an NS accordion plugin, but I think the goal here should be possible with straight code, especially because in my case I want to customize a fair bit.
I have run into two problems:
1) How do I isolate the click on category itself? The grouping function seems to "hide" the category title programmatically--I have not been able to know when the user clicks on it (instead of registering just clicks on the whole group) and have not been able to style that group header.
2) Once the category header is clicked, how do I show / hide the entries below? Normally, I would use something like visibility="{{isClicked ? 'visible' : 'collapsed'}}, but that is not working with RadListView.
Here is some sample code to give a better sense of the goal:
html:
<GridLayout >
<RadListView [items]="places" selectionBehavior="Press" (itemSelected)="itemSelected($event)" [groupingFunction]="myGroupingFunc" >
<ng-template tkListItemTemplate let-place="item" >
<StackLayout>
<Label [text]="place.city"></Label>
<Label [text]="place.people" ></Label> //NOTE: I have not yet determined how to show this second level data within RadListView.
</StackLayout>
</ng-template>
</RadListView>
</GridLayout>
ts:
import { Component, OnInit, } from "#angular/core";
import { Router, } from "#angular/router";
import { ObservableArray } from "tns-core-modules/data/observable-array";
import { RadListView, ListViewEventData, } from "nativescript-ui-listview";
#Component({
selector: "Sample",
moduleId: module.id,
templateUrl: "./sample.component.html",
})
export class SampleComponent implements OnInit {
public places = [
{country: 'US', city: 'New York', people: [{name: 'Bill', age: 22}, {name: 'Suzy', age: 23} ] },
{country: 'US', city: 'Los Angeles', people: [{name: 'Sarah', age: 21}, {name: 'Barb', age: 23} ] },
{country: 'Canada', city: 'Toronto', people: [{name: 'Fred', age: 30}, {name: 'Ted', age: 31} ] },
{country: 'England', city: 'London', people: [{name: 'Jim', age: 22}, {name: 'Joe', age: 19} ] }
]
constructor() {
}
myGroupingFunc(value) {
return value.country;
}
itemSelected(args) {
/***is there a way this can isolate the tap on country name?*****/
}
}

To make the header entries clickable, you can use tkGroupTemplate with categories (<ng-template tkGroupTemplate let-category="category"> ), as further detailed in the answer here.
However, toggling show and hide entries is not currently supported in iOS with Nativescript. See further discussion here. From this discussion, it looks like you can show/hide entries. However, on iOS, the app will not shrink the area on hide or enlarge the area on show. The area will stay the same as it is when loaded, whether or not the entries are shown. It looks like Android does not have this limitation.
The nativescript accordion plugin provides some help for toggling, even though some features have yet to be ironed out. If anyone is desparate for an accordion on Nativescript iOS, that is probably the place to start.

Related

Vuetify v-treeview. Change the text

I use NuxtJs and Vuetify for one project. I need to create a treeview so I would like to do it with v-treeview.
I have a problem with the node name.
Here are my data:
items: [
{
id: 1,
data: {
name: 'Application :',
id: '1',
},
children: [
{},
],
},
}
Here the frontend
<v-treeview :items="items"></v-treeview>
So I would like to have data.name in text but I can't get it. Do you have an idea?
Thanks
Add the item-text property to your v-treeview tag to specify what the value to be displayed is
:item-text="data.name"
you can use the label slot inside your v-treeview like :
<v-treeview :items="items">
<template v-slot:label="{item}">
<div class="v-treeview-node__label">{{item.data.name}}</div>
</template>
</v-treeview>

Vue-native: Dynamically created touchable-opacity are all pressed at the beginning

When i create touchable-opacity or buttons using v-for loop, the on-press functions of all buttons are called even though i haven't touch any of them. But there isn't any problem with normal button using the same function as handler.
<view v-for="taskDay in buttons" :key="taskDay.id" class="task-day">
<touchable-opacity
v-for="task in taskDay.next"
:key="task.id"
:on-press="handleTouch(task.id)"
class="task">
</touchable-opacity>
</view>
methods: {
handleTouch: function(id) {
console.log(id);
}
},
There isn't much on the internet about vue native. Can anyone help?
I am facing exactly the same issue....
UPDATE: I dived more deep in the topic, and it turned out is a known issue in native base.
Checkbox is touchable opacity in react native, and button as well with a composition of views in some order, thats why you have problems in both cases.
See the native base issue in github:
https://github.com/GeekyAnts/NativeBase/issues/3038
However, I could find a workaround. This is not exactly a checkbox, I use tick icon to display that the item is checked, and I iterate through a touchable opacity from native base. But with some styling you can create a checkbox I am sure.
<scroll-view
:content-container-style="{
contentContainer: {
paddingVertical: 20
}
}"
>
<touchable-opacity
v-for="(item, index) in dataArray"
:key="index"
:onPress="
() => {
checkItem(index)
}
"
>
<text>{{ item.time }} - {{ item.name }}</text>
<image
:style="{ height: 15, width: 15, marginLeft: 15 }"
:source="require('../../../assets/icons/done.png')"
v-if="item.checked"
/>
</touchable-opacity>
</scroll-view>
In the checkItem method I use splice and replace the item to preserve reactivity:
methods: {
checkItem(index) {
this.dataArray[index].checked = true
this.dataArray.splice(index, 1, this.dataArray[index])
}
},
My dataArray is an array like that:
[{id: 1, name: 'Name', checked: true}, {id: 2, name: 'Name', checked: false}]
I hope it will help to resolve your problem.

nativescript-vue dataform does not update the source data

anyone can help?
i have this one page app to show the problem:
if you modify a field and then press 'save' at the top the changed field is not shown on the console...
<template>
<Page>
<ActionBar>
<Label text="SAVE" #tap="saveScreen()" />
</ActionBar>
<StackLayout>
<RadDataForm :source="person"/>
</StackLayout>
</Page>
</template>
<script>
export default {
data () {
return {
person: {
name: 'John',
age: 23,
email: 'john#company.com',
city: 'New York',
street: '5th Avenue',
streetNumber: 11,
},
};
},
methods: {
saveScreen() {
console.log('=======personName: ' + JSON.stringify(this.person))
}
}
}
</script>
<style>
</style>
i realize this is pretty much a basic question, i searched the internet for an answer however could not find it...
thanks in advance for your help.
Regards,
Hans
RadDataForm is a little bit tricky to work with since it doesn't bind data automatically so you'll have to add some events to get changed data.
Initial data is used to create form and on change data is saved to another object so you can listen to propertyCommitted event and get editedObject.
<RadDataForm :source="person" #propertyCommitted="onPropertyCommitted" />
data() {
return {
person: {
name: "John",
age: 23,
email: "john#company.com",
city: "New York",
street: "5th Avenue",
streetNumber: 11
},
committedPerson: {}
};
},
methods: {
onPropertyCommitted (data) {
this.committedPerson = data.object.editedObject
},
saveScreen () {
console.log(this.committedPerson);
}
}
Don't know if this is the best way to do it in Vue but I see that there are open issues on github regarding this and some workarounds are posted but none for Vue.
It should be explained better in official docs.
Here is working example https://play.nativescript.org/?template=play-vue&id=98Xyjv&v=5
And here you can find some examples on validation, grouping etc.https://github.com/telerik/nativescript-ui-samples-vue/tree/master/dataform/app/examples
Here is my answer for this. Look at the save function.
<StackLayout>
<StackLayout orientation="vertical" backgroundColor="lightgray">
<RadDataForm
id="myDataForm"
:source="record"
v-on:propertyCommitted="save"/>
</StackLayout>
<script>
import { mapState } from 'vuex'
import { getViewById } from "tns-core-modules/ui/core/view";
export default {
data() {}
},
methods:{
save(){
console.log('save')
let data = args.object
var dataform = getViewById(data, "myDataForm");
console.log(dataform.editedObject)//<--updated Data Here
},
}
computed: mapState({
record(state){
return record = this.$store.getters.record;
}
};

How to catch click on category header with RadListView grouping function? (Nativescript)

I had previously asked about a few items re: RadListView's grouping function here. I didn't get an answer, so wanted to try to focus on hopefully the simplest part: how do I catch the click event on a category header?
Normally, this would be pretty easy, like <Label text="group.category" (tap)="youClickedTheCategory()"></Label>.
But using the grouping function with RadListView, the category does not have an html entry, so how do I know if the user clicks on the category header instead of somewhere else in the group?
If example code is helpful:
html:
<GridLayout>
<RadListView [items]="places" [groupingFunction]="myGroupingFunc">
<ng-template let-place="item" >
<StackLayout>
<Label [text]="place.city"></Label>
</StackLayout>
</ng-template>
</RadListView>
</GridLayout>
ts:
public places = [
{country: 'US', city: 'New York'},
{country: 'US', city: 'Los Angeles'},
{country: 'Canada', city: 'Toronto'},
{country: 'England', city: 'London'}
]
constructor() {
}
myGroupingFunc(value) {
return value.country;
}
Result would be:
Canada
--Toronto
England
--London
US
--New York
--Los Angeles
Goal: know if the user clicks on the country category header (here, Canada , England, or US)--instead of the user clicking on the whole group.
Using Nativescript Angular (for iOS).
I have found the answer, based on this github discussion here. The key is the tkGroupTemplate in RadListView. For NativeScript (and iOS--probably works for Android too), if you want to have a list that has category headers and entries below, and you want to be able to click on the category headers, the present method is to use tkGroupTemplate.
Here is an example:
$ tns plugin add nativescript-ui-listview
component html:
<GridLayout>
<RadListView [items]="places" [groupingFunction]="myGroupingFunc">
<ng-template tkListItemTemplate let-place="item">
<StackLayout>
<Label [text]="place.city" (tap)="listEntryTap(place.city)"></Label>
</StackLayout>
</ng-template>
<ng-template tkGroupTemplate let-country="category">
<StackLayout ios:height="25">
<Label [text]="country" (tap)="headerTap(country)"></Label>
</StackLayout>
</ng-template>
</RadListView>
</GridLayout>
ts: (component ts file)
public places = [
{country: 'US', city: 'New York'},
{country: 'US', city: 'Los Angeles' },
{country: 'Canada', city: 'Toronto'},
{country: 'England', city: 'London'},
{country: 'US', city: 'Chicago'},
{country: 'Canada', city: 'Calgary'}
]
...
constructor(){}
...
myGroupingFunc(value) {
return value.country;
}
headerTap(country){
console.log('you tapped this country header: ' + country)
}
listEntryTap(city){
console.log('you tapped this city entry: ' + city)
}
module.ts: (module for the component--if using lazy loading of components. If not using lazy loading, this probably would go in the main app.module.ts file)
import { NativeScriptUIListViewModule } from "nativescript-ui-listview/angular";
#NgModule({
imports: [
...
NativeScriptUIListViewModule
]
...
And that should produce the following, with headers (countries) and entries (cities) separately clickable:
Canada
Toronto
Calgary
England
London
US
New York
Los Angeles
Chicago
It looks like this comes with some default formatting (the headers have a different background color automatically)--but you can override that with your own styles.
Without the ios:height="25"(or whatever height) some of the category headers go over the entries.
Otherwise, though, this seems to work for iOS and NativeScript 5.0+ (and, I assume, earlier versions too).

Kendo Editor snippets and MVVM

Is it possible to specify a source for available 'snippets' for the Editor widget. I'd like to put store them in a separate array (or even better, retrieve them from a remote data source).
I've tried something like:
<script type="text/x-kendo-template" id="editor">
<textarea name="test" data-bind="value:test" data-role="editor" data-tools="['insertHtml']" data-insert-html="snippets"></textarea>
</script>
where snippets is the array as per the Editor demo, but this doesn't work.
It this supported?
Maybe no longer relevant, but for further reference:
<textarea data-role="editor"
data-tools="['bold', 'italic', 'underline', 'strikethrough', 'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull',
{ name: 'insertHtml',
items: [{ text: 'title', value: '{{title}}' },
{ text: 'description' , value: '{{description}}' },
{ text: 'link' , value: '{{link}}'},
{ text: 'notes' , value: '{{notes}}'}]
}]"
data-bind="value: emailForm.body"></textarea>
This allows you to add snippets to the toolbar using the MVVM method. To get them from a remote datasource you most likely need to do this by finding the kendo control when it is rendered and then set a different datasource with a similar key/value structure.

Resources