Store different arrays in Ionic Storage - ionic-framework

I'm trying to use a submit page with a bunch of different fields on it to submit details about a single beehive (name, location, comments, etc.). I'm planning to use Ionic Storage, and have the data go into an array if that's the best way to do it, then use a list to display all the items, which you can then click to go to the specific details about the hive.
So far I'm trying to do something like this, but not sure if this is on the right track or not:
submitHive() {
this.navCtrl.push(ViewHivePage)
let data={'name': this.name, 'location': this.location, 'address': this.address, 'date': this.date, 'weight': this.weight, 'comments': this.comments}
console.log(data)
this.hiveData={
name:this.name,
location:this.location,
address:this.address,
date:this.date,
weight:this.weight,
comments:this.comments
}
Pushing the data from the input fields, then going to a new page to display the details. I'm using [(ngModel)] to push the data, is this on the right track?
Thanks!

Better If You can use angular Forms instead of using multiple [(ngModel)]. Because of Angular Form implementation is more clear than this. Try to use like bellow
_dataForm: FormGroup;
_hiveData;
ngOnInit() {
this.initForm();
}
initForm() {
this._dataForm = new FormGroup({
name: new FormControl("", Validator.required),
...
});
}
saveData() {
// check the validation if needs
this.hiveData = this._dataForm.value;
// save the data
this.navCtrl.push(ViewHivePage, {hiveData: this.hiveData});
// you can take this data from other component using navparams
}
template
<form [formGroup]="_dataForm">
<input type="text" formControlName="name">
...
</form>

Related

How to get city name from ion-input field in ionic 3?

Here I want to have only city name how simply I can get, I followed some blogs but kind of confused.
my html
<ion-input type="text" [(ngModel)]="default.city"></ion-input>
I am expecting something like
this.cityName = somefunction(inputText) {
...
return city;
}
I am looking for some ionic cordova plugin to autocomplete the typed location and list down the possible location and select one of them.
Depending on when you wish to show you autosearch results you can bind it to an event
<ion-input type="text" [(ngModel)]="default.city" (ionBlur)="someFunction()"></ion-input>
If you wish the autosearch results to come after he clicks out of the input box
you could use
(ionChange)="someFunction()" or (input)="someFunction()"
also if you need to
For Reverse geocoding you could use the geocoder plugin
https://github.com/sebastianbaar/cordova-plugin-nativegeocoder plugin
somefunction(inputText) {
this.nativeGeocoder.forwardGeocode('Berlin', options)
.then((coordinates: NativeGeocoderForwardResult[]) => {
this.autosearchresult = coordinates[0] // If you want one
})
.catch((error: any) => console.log(error));
}
and display it on the somwhere in the dom
<div (click)="completeauto()" *ngIf="showAutosearch">{{autosearchresult}}</div>
Keep in mind that you will also need some method to remove the search results and set the searchbar to the clicked value. If the user clicks on it.
Additionally if you have a Google Cloud Account you can activate the Google Places API which is more Robust than the Ionic Native version but you would require a credit card enabled account for it.
MapBox API also provides geocoding but I am not all that familiar with it.
If you have an Array of Object City cities, you can filter it by the name of the city in the following way
searchCityByName(searchText: any) {
const length = searchText.length;
console.log('filtering');
console.log(length);
if (length > 0) {
this.cities= this.cities.filter(city=> {
return city.name.toLowerCase().indexOf(searchText.toLowerCase()) >= 0;
});
}
}

How to seperate Vue logic in a laravel app based on layout and page templates

I have a laravel app and a Vue instance attached to the body (or a div, just inside the body).
const app = new Vue({
el: '#app'
});
I think it makes sense to use the Vue instance for stuff relating to the layout (eg header, nav, footer logic).
Now I have a form that is visible on a specific route (e.g. example.com/thing/create). I want to add some logic to it, e.g. hiding a field based on selected option in the form. It is logic meant for just this form (not to be reused). I prefer not to put all the logic inline with the form but put it in the app.js. I could put it in the Vue instance bound to the body but that sounds odd as it only applies to the form that is much deeper into the dom.
I want to leave the markup of the form in the blade template (that inherits the layout).
I tried creating a component but am not sure how to bind this inside the main Vue instance. What is the best way to handle things for this form, put it in the app.js and have it somewhat structured, putting the variables somewhat into scope. Or is it really necessary to remove the main Vue instance bound to the full layout code?
What I tried was something like this, but it does not work (attaching it to the <form id="object-form"> seems to fail:
var ObjectForm = {
template: function() { return '#object-form'},
data: function() {
return {
selectedOption: 1
}
},
computed: {
displayField: function() {
// return true or false depending on form state
return true;
}
}
};
Things do work if I remove the #app Vue instance or when I put everything directly in the app Vue instance. But that seems messy, if I have similar variables for another form they should be seperated somewhat.
I would appreciate some advice regarding the structure (differentiate page layout and page specific forms) and if possible some example to put the form logic inside the main app.js.
I hope this helps kind of break things down for you and helps you understand Vue templating.
It is best to take advantage of Vue's components. For you it would look something like this. Some of this code depends on your file structure, but you should be able to understand it.
In your app.js file (or your main js file)
Vue.component('myform',require('./components/MyForm.vue'));
const app = new Vue({
el: "#app"
});
Then create the MyForm.vue file
<template>
<form>
Put Your Form Markup Here
</form>
</template>
<script>
// Here is where you would handle the form scripts.
// Use methods, props, data to help set up your component
module.exports = {
data: function() {
return {
selectedOption: 1
}
},
computed: {
displayField: function() {
// return true or false depending on form state
return true;
}
},
methods: {
// add methods for dynamically changing form values
}
}
</script>
Then you will be able to just call in your blade file.
<myform></myform>
I found out how to do it. The trick was to use an inline template. Surround the form in the view with:
<object-form inline-template>
<form>...</form>
</object-form>
Where object-form is the name of the component. In the ObjectForm code above I remove the template, like this:
var ObjectForm = {
data: function() {
return {
selectedOption: 1
}
},
computed: {
displayField: function() {
// return true or false depending on form state
return true;
}
}
};
I attach the component within the root vue app like this:
const app = new Vue({
el: 'body',
components: {
'object-form': ObjectForm
}
});
This way I can use the form as it was generated from the controller and view and I can separate it from the root (attached to body) methods and properties.
To organize it even better I can probably store the ObjectForm in a seperate .vue file the way #Tayler Foster suggested.

Rxjs workflow for MongoDB Document References

I am developing an application on Ionic2/rc0. I got a ReplaySubject on a singlenton service that keeps the current user consistent across the whole app. It all works fine, I can subscribe to it and get a User object as easy as
this._user.Current.subscribe(user=>{ console.log(user)});
The User object looks like this
User {
confirmed:true
devices:["57f65werwe343bn8843f7h","7yr3243h5429hf2hjd"]
friends:["t245y53h65346htyh","356ytrer75dfhg43we56df"]
email:"francescoaferraro#gmail.com"
id:"57f6525e926bbc7615fc5c5c"
notification:false
password="$2a$04$.Fk/8eMj18ZrkfurbbdP4uT3yOs7Lb9db74GkNfgtABVY.ez2Q0I."
picture:"https://api.cescoferraro.xyz/kitty"
role:"master"
username:"cesco"
}
As you can see my backend is using MongoDB with One-to-Many Relationships with Document References as described here.
I have created a devices tab where I want to display all data about those user devices, but I need to call this._devices.info for each one of current.devices and concat the result back to TrueDevices
#Component({
template: `
<ion-header>
<ion-navbar>
<ion-title>Tabs</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<h2>Device:list</h2>
<h2 *ngFor="let item of devices | async">{{item}}</h2>
<button ion-button (click)="readDevice()">Read Random Device</button>
</ion-content>
`
})
export class DeviceComponent {
devices: Observable<string[]>;
TrueDevices: Observable<Device[]>;
constructor(public _user: UserService, public _device: DeviceService) {
this._user.Current.subscribe(user=>{ this.devices = Observable.of(user.devices)});
// Get current User
// call this._devices.info for each one of current.devices
// concat the result back to TrueDevices
this._user.Current
.subscribe((result) => { console.log(result) });
}
readDevice(){
console.log(this.devices);
this._device.info(this.devices.value[0]).subscribe(data=>console.log(data))
}
}
I will need to repeat the same procedure to the friends tab and so on. I am pretty sure there are a couple operators that would do the magic, but I am fairly new to rxjs and not familiar with all of them. Whats the right approach?
this._user.Current
.switchMap(user => Observable.from(user.devices)) // after this line, you have an Observable<string>
.mergeMap(device => this._device.info(device)) // each device will be mapped to another observable(or stream), and all the streams will be merged together
.toArray() // wait for all the streams to complete and reduce all the results into an array.
.subscribe(array => console.log(array));
or go to the gitter room:
https://gitter.im/Reactive-Extensions/RxJS

Trying to think about how to build a multi step form in angular 2

I am trying to build a small, 3 step form. It would be something similar to this:
The way I did this in react was by using redux to track form completion and rendering the form body markup based on the step number (0, 1, 2).
In angular 2, what would be a good way to do this? Here's what I am attempting at the moment, and I'm still working on it. Is my approach fine? Is there a better way to do it?
I have a parent component <app-form> and I will be nesting inside it <app-form-header> and <app-form-body>.
<app-form>
<app-header [step]="step"></app-header>
<app-body [formData]="formData"></app-body>
</app-form>
In <app-form> component I have a step: number and formData: Array<FormData>. The step is just a index for each object in formData. This will be passed down to the header. formData will be responsible the form data from user. Each time the form input is valid, user can click Next to execute nextStep() to increment the index. Each step has an associated template markup.
Is there a better way to do something like this?
don't overdo it, if it is a simple form you don't need to use the router or a service to pass data between the steps.
something like this will do:
<div class="nav">
</div>
<div id="step1" *ngIf="step === 1">
<form></form>
</div>
<div id="step2" *ngIf="step === 2">
<form></form>
</div>
<div id="step3" *ngIf="step === 3">
<form></form>
</div>
It's still a small template, and you kan keep all of the form and all the data in one component, and if you want to you can replace the ngIf with something that switches css-classes on the step1,2,3 -divs and animate them as the user moves to the next step
If you want to keep things extensible, you could try something like this:
<sign-up>
<create-account
[model]="model"
[hidden]="model.createAccount.finished">
</create-account>
<social-profiles
[model]="model"
[hidden]="model.socialProfiles.finished">
</social-profiles>
<personal-details
[model]="model"
[hidden]="model.personalDetails.finished">
</personal-details>
</sign-up>
export class SignUpVm {
createAccount: CreateAccountVm; //Contains your fields & finished bool
socialProfiles: SocialProfilesVm; //Contains your fields & finished bool
personalDetails: PersonalDetailsVm; //Contains your fields & finished bool
//Store index here if you want, although I don't think you need it
}
#Component({})
export class SignUp {
model = new SignUpVm(); //from sign_up_vm.ts (e.g)
}
//Copy this for personalDetails & createAccount
#Component({})
export class SocialProfiles {
#Input() model: SignUpVm;
}

Ember Observe DOM Element

I have an
<input type="file">
in my DOM. Is it possible to trigger an action with Ember techniques if the file in this input changes, or do I have to use third party libs like jquery-observe?
Yes, of course it is possible.
You can create a file field component as follows:
// put in components/file-field.js if you are using ember-cli
import Ember from "ember"
export default Ember.TextField.extend({
type: 'file',
attributeBindings: ['multiple'],
multiple: false,
change: function(event) {
var input = event.target();
if (!Ember.isEmpty(input.files)) {
this.sendAction("filesChanged", input.files);
}
}
});
Now place this in your template in place of your <input type="file">
{{file-field filesChanged="uploadFile"}}
Then in the controller or in one of your routes where this action will bubble, define your uploadFile action:
actions: {
uploadFile: function(files) {
// put your ajax call to upload the file(s) here
}
}
Although this is enough to get you started learning, I would definitely recommend using something like ember-cli-uploader for this in a real application.