Svelte Native ListView - Horizontal - nativescript

I try out and build my first App on Svelte Native. I develop this for an Tablet.
The standard ListView only supports vertical stacking.
I need this for horizontal.
This part only works for vertical:
<listView items="{listOfItems}" on:itemTap="{onItemTap}">
<Template let:item>
<!-- Shows the list item label in the default color and style. -->
<label text="{item}" />
</Template>
</listView>
<script>
import { Template } from 'svelte-native/components'
let listOfItems = ['one', 'two', 'three']
</script>
I also try this:
Here i have the Problem that nothing is showing.
{#each one as ones}
<button on:tap={addToList(ones)} text="{ones.name}" class="prod-btn" />
{/each}
So i need help to show a list of objects in an horizontal view.

Related

NativeScript - Change Label into TextView/TextField with a Button

I am learning to make an app in NativeScript (Angular 2). In my item page, I want to have a button so that when I press it, I can change Label into TextView/TextField for editing the information of the item.
I know that I can use editable in TextView but I still want to know if it is feasible to have the button with that functionality. Thank you !!
item.component.html:
<StackLayout>
<Label class="h3" text="Name: {{ item.get_name() }}" textWrap="true">
</Label>
<Label class="h3" text="Credit: {{ item.get_credit() }}"></Label>
<Button class="btn" text="Edit" (tap)="change()"></Button>
</StackLayout>
<!-- After pressing the button -->
<StackLayout>
<TextView class="h3" [text]="item.get_name()" textWrap="true">
</TextView>
<TextView class="h3" [text]="item.get_credit()"></TextView>
<Button class="btn" text="Save" (tap)="change()"></Button>
</StackLayout>
This can be done in many ways, but one common way is by changing visibility of control and binding it to a variable / property in the code behind.
in your component html:
Then on your component ts or code-behind you can handle it in the change method:
class MyComponentSample {
isLabelMode: boolean = true; // Set to true if you want label to show by default or false if TextView as default
change() {
this.isLabelMode = !isLabelMode; // Basically you are toggling the mode here.
}
}

Adding horizontal ScrollView to code-generated GridLayout

I have this sample code that works as I want:
<ScrollView orientation="horizontal">
<GridLayout columns="*,*,*,*,*,*" >
<Label class="gridlabel" col="0" text="Monday" />
<Label class="gridlabel" col="1" text="Tuesday" />
<Label class="gridlabel" col="2" text="Wednesday" />
<Label class="gridlabel" col="3" text="Thursday" />
<Label class="gridlabel" col="4" text="Friday" />
<Label class="gridlabel" col="5" text="Saturday" />
</GridLayout>
</ScrollView>
That is, the labels within the GridLayout scroll horizontally.
I have a component that generates a GridLayout, and now I need to wrap that in a horizontal ScrollView.
That is, I for each label:
let label = new Label();
// Add tap event handler for each tab
label.on("tap", function () {
onTabTap(label, "tabTap");
}.bind(label));
label.id = key;
label.text = key;
label.class = "gridtab";
this.addColumn(new ItemSpec(1, GridUnitType.STAR));
GridLayout.setColumn(label, i);
GridLayout.setRow(label, 0);
this.addChild(label);
But when I try to add the ScrollView, I get errors. If I try to add the labels to the ScrollView, such as scrollView.addChild(label) (where scrollView is an instance of ScrollView), I get "scrollView.addChild is not a function". (See this similar SO post). If, as suggested in the mentioned post, I use scrollView.content = this; then I get the error, Error: View already has a parent.
So, the question is, from code, how do I replicate the hierarchy from my sample xml? That is, how can I wrap the generated GridLayout in a horizontal ScrollView?
Edit 7/17/2020
Upon reflection, I don't think this can work given my component's current design. That is, it subclasses GridLayout, and I want the generated GridLayout to be wrapped by a ScrollView, but that would be external to the content generated by the component, yes? It almost seems I'd need to subclasss ScrollView, and then generate the GridLayout within.
So, I was ultimately able to resolve this by subclassing StackLayout, then within the StackLayout adding a ScrollView, and within the ScrollView adding the GridLayout. The "magic" is:
scroll.content = grid;
this.addChild(scroll);
Where scroll is the ScrollView instance, and grid is the GridLayout instance.
Then, after spending a day on this I found I didn't actually need horizontal scrolling after all, but at least I know what to do should the need arise.

How to show a button if there are no items in a ListView?

I have the following structure:
<ScrollView tkMainContent>
<ListView [items]="students$ | async" class="list-group" *ngIf="students$">
<ng-template let-student="item">
<StackLayout>Student details go here</StackLayout>
I'm not able to show a button inside the ScrollView when there is no student in my list.
How can I still show the button?
Note: I'm testing on a real iOS device.
<FlexboxLayout flexDirection="column">
<GridLayout class="page-content" id="placeholderLayout" visibility="{{ hasContent ? 'collapse' : 'visible' }}">
<Label class="page-icon fa" text=""></Label>
<Label class="page-placeholder" style="white-space: normal" text="Click the camera button to add image"></Label>
</GridLayout>
<ScrollView>
<-- List View Here -->
</ScrollView>
</FlexboxLayout>
I use something like this on NS Core, to show placeholder content. The way to set visibility might be different in angular, but a similar markup should work for you.
In the component.ts, you should take care to evaluate if there is content to show in list view, if there are, then set hasContent to true, and false otherwise.
Hope that helps :) let me know if you face any trouble while implementing this.

A modal list-picker

I am trying to implement a list where I should pick an item from it, I am trying to use a ListPicker:
<StackLayout verticalAlignment="top">
<ListPicker id="inquiryType" items="{{ inquiryTypeItems }}" />
</StackLayout>
Is there any way to make the ListPicker modal, and show it by clicking on a readonly TextField?
I am using Javascript on Nativescript.
Thanks!
Put ListPicker to modal dialog wont be good idea as u need to create platform dependend creating and processing that picker
So first approach would be dialogs actions and on tap open dialog with options,
array of options, only strings
http://docs.nativescript.org/cookbook/ui/dialogs#action
Example (taken from link above if it happens it wont work for u and little rewrited for your case):
var options = {
title: "Inquiry Type",
message: "Choose inquiry type",
cancelButtonText: "Cancel",
actions: inquiryTypeItems
};
dialogs.action(options).then((result) => {
console.log(result);
});
or as second approach,
U can set ListPicker as hidden on load of page after tapping on something(definitely not TextField, as u can get problem with showing keyboard, either Label or Button) show ListPicker with animation or visibility property and on change or maybe on Done button which would be together with ListPicker it would let people to choose from list of items :)
If u have other data together with other properties better for second approach but if u have some simple array of strings u can use first one
I am not sure how you would do this in plain NativeScript, however, if you are using Angular2, then you can use an angular modal and then nest the nativescript ListPicker inside that.
So the README of the Angular2 Modal Project describes creating ui agnostic modals very thoroughly. Then in its content, you would do something like:
<div class="container-fluid custom-modal-container">
<div class="row custom-modal-header">
<div class="col-sm-12">
<h1>A Custom modal design</h1>
</div>
</div>
<div class="row" [ngClass]="{'myclass' : shouldUseMyClass}">
<div class="col-xs-12">
<div class="jumbotron">
<h1>Pick Something:</h1>
<ListPicker id="inquiryType" items="{{ inquiryTypeItems }}" />
</div>
</div>
</div>
</div>`
Here shows how the components might fit together.
You can see the issue which track supporting this in NativeScript.

How to add an activity-indicator on a page level?

I would like to add an activity-indicator widget in my login page but I would like it to cover the whole screen, so I can prevent double click on the Login button.
Any idea, thanks!
If you wrap everything in a GridLayout, add a StackLayout as the last item in the row you want to cover. The StackLayout by default will cover the whole screen. Then you can show/hide via data. For example:
<GridLayout>
<StackLayout>
// All your page content goes here!
</StackLayout>
<StackLayout class="dimmer" visibility="{{showLoading ? 'visible' : 'collapsed'}}"/>
<GridLayout rows="*" visibility="{{showLoading ? 'visible' : 'collapsed'}}">
<ActivityIndicator busy="true" />
</GridLayout>
</GridLayout>
I have a "dimmer" StackLayout that I animate to be semi transparent black, then the Activity Indicator sits on top.
not sure what layout you have i will only put example(somehow simplified) from my project
Inside page u can put something like this, both StackLayout and ActivityIndicator are inside GridLayout which takes whole size of page
<GridLayout rows="*" columns="*">
<StackLayout visibility="{{ showLogin ? 'visible' : 'collapse'}}" row="0" column="0">
<!--Login form, as you have defined-->
</StackLayout>
<!--Indicator on whole page, colSpan and rowSpan force ActivityIndicator to takes whole page-->
<ActivityIndicator visibility="{{ !showLogin ? 'visible' : 'collapse'}}" busy="{{ !showLogin }}" rowSpan="1" colSpan="1" row="0" column="0" />
</GridLayout>
And inside javascript code
/*somehow add showLogin property to bindingContext*/
page.bindingContext.set("showLogin",false) //false for show ActivityIndicator
/*or*/
page.bindingContext.set("showLogin",true) //true for show form
But best would be to put to already defined Observable which you should have assigned to bindingContext
So based on showLogin property u will get visible either ActivityIndicator(on whole page) or form
Not sure if i forgot something but if something, write comment :)
The activity indicator on its own won’t prevent dual submissions of your forms. In addition to displaying an ActivityIndicator, you should also set the isEnabled flag on your Button UI components to false during the submission. For example:
<!-- template -->
<Button [isEnabled]="!isAuthenticating" (tap)="submit()"></Button>
// JavaScript/TypeScript
export class LoginComponent {
isAuthenticating = false;
submit() {
this.isAuthenticating = true;
doTheActualLogin()
.then(() => {
this.isAuthenticating = false;
});
}
}
You can find a complete implementation of a login that prevents dual submissions and uses an ActivityIndicator in the NativeScript Groceries sample. Take a look at how the isAuthenticating flag is used in this login folder for the specific implementation.

Resources