How to reference a global function in a Vue component? - javascript

I have a Vue component that has a 'select state' dropdown element. I want to add a js function that populates the options with the 50 states instead of having to hard code them. I will also have this dropdown in a couple other places so I want this function to be accessed from outside the component. What is the best way to accomplish this?
<template>
<div class="section" v-bind:class="sectionClass" data-mh="group3">
<h3>{{sectionTitle}}</h3>
<div class="section-content display-area">
<i class="icon icon-health img-left"></i>
<form>
<div class="row mt">
<div class="col-xs-12 col-sm-8">
<div class="same-height-parent">
<div class="same-height">
<input type="text" class="form-control" placeholder="Enter Name">
</div>
<div class="same-height">
<select name="state" id="state" class="form-control" tabindex="9">
<option value="">- Select State -</option>
</select>
</div>
</div>
<!-- same-height-parent -->
</div>
<div class="col-xs-12 col-sm-4">
<button type="submit" class="btn btn-success btn-block btn-fz20">Search</button>
</div>
</div>
</form>
</div>
</div>
</template>
<script>
export default {
name: 'nameSearch',
data: function() {
return {
sectionTitle: 'Name Search'=
}
}
}
</script>

you may want to export the function from some other file, this is simply a case of declaring it the way you want.
in some other file...
// utils.js
export function createOptions (someArg) {
let options = [ ... ]
return options
}
in your .vue file
<script>
import { createOptions } from './utils'
export default {
...
data () {
return {
options: createOptions()
}
}
}
</script>
You may also want to try snovakovic's advice to externalise the dropdown component instead, whatever brings you more flexibility

Why not just create states components that handles drop-down and then include that component everywhere where it's used.
If you want just a function then create js file that expose that function and than import that file inside component.

Related

capture html within a component

capture the content of a component child, this component and this in turn calls another, in this second component there is an html, in this second component in the code javascripot capture this component to use it
first component, has as component child -- field --
<template>
<div id="login">
<field type="select" name="lang">
<option>one</option>
<option>zero</option>
</field>
</div>
</template>
second component, is field
<template>
<div class="field input">
<label>{{label}}</label>
<div v-html="htmlfield"> </div>
</div>
</template>
<script>
export default {
props: ['type'],
computed : {
htmlfield : function(){
switch (this.type) {
case 'select':
return `<select ${attr}>**__here__**</select>`; break;
}
},
},
}
</script>
__here__ I want to put the options indicated in the first component
I would like to be able to capture with javascript the html of a component
It looks like you're trying to create a universal <field> that you can pass the type of input you want.
Can I suggest a different approach?
First component
<template>
<div id="login">
<field type="select" :options="options" name="lang"></field>
</div>
</template>
<script>
export default {
data () {
return {
options: [
{ label: 'one', value: 'value1' },
{ label: 'zero', value: 'value2' }
]
}
}
}
</script>
Second component:
<template>
<div class="field input">
<label>{{ label }}</label>
<select v-if="type === 'select'">
<option v-for="option in options" :value="option.value" :key="option.value">{{ option.label }}</option>
</select>
<input v-if="type === 'text'" type="text">
<input v-if="type === 'number'" type="number">
</div>
</template>
<script>
export default {
props: ['label', 'type', 'options']
}
</script>
Here, instead of writing the <option> elements in the parent template, we create option objects in an array called options and pass it to <field> as a prop, then we can render the <option> elements in the child IF the 'type' === 'select'.

Table not showing the data from database in laravel vue component

For the past few days, I have been following a tutorial about VUE application from a really good youtuber. I was following each and every step as it was mentioned in the tutorial when suddenly I have come to an abrupt halt. This is because the data from my database is not showing up in the frontend. The database does show that I am storing the data properly, and there are no errors whatsoever.
The video where I got stuck on is: https://youtu.be/bUXhGw4aQtA
Here is the code for the index in my controller
public function index()
{
return User::latest()->paginate(10);
}
Here is the app.js
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
import {
Form,
HasError,
AlertError
} from 'vform'
window.Form = Form;
Vue.component(HasError.name, HasError)
Vue.component(AlertError.name, AlertError)
import VueRouter from 'vue-router'
Vue.use(VueRouter)
let routes = [{
path: '/dashboard',
component: require('./components/Dashboard.vue').default
},
{
path: '/profile',
component: require('./components/Profile.vue').default
},
{
path: '/users',
component: require('./components/Users.vue').default
}
]
const router = new VueRouter({
mode: 'history',
routes // short for `routes: routes`
})
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
// const files = require.context('./', true, /\.vue$/i);
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default));
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
const app = new Vue({
el: '#app',
router
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<div class="container">
<div class="row mt-5">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">Users Table</h3>
<div class="card-tools">
<button class="btn btn-success" data-toggle="modal" data-target="#addNew">Add new <i class="fas fa-user-plus"></i></button>
</div>
</div>
<!-- /.card-header -->
<div class="card-body table-responsive p-0">
<table class="table table-hover">
<tbody>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Type</th>
<th>Registered At</th>
<th>Modify</th>
</tr>
<tr v-for="user in users.data" :key="user.id">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.email}}</td>
<td>{{user.type | upText}}</td>
<td>{{user.created_at | myDate}}</td>
<td>
<a href="#" >
<i class="fa fa-edit blue"></i>
</a>
/
<a href="#">
<i class="fa fa-trash red"></i>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- /.card -->
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="addNew" tabindex="-1" role="dialog" aria-labelledby="addNewLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addNewLabel">Add Users</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<form #submit.prevent="createUser">
<div class="modal-body">
<div class="form-group">
<input v-model="form.name" type="text" name="name"
placeholder="Name"
class="form-control" :class="{ 'is-invalid': form.errors.has('name') }">
<has-error :form="form" field="name"></has-error>
</div>
<div class="form-group">
<input v-model="form.email" type="text" name="email"
placeholder="email"
class="form-control" :class="{ 'is-invalid': form.errors.has('email') }">
<has-error :form="form" field="email"></has-error>
</div>
<div class="form-group">
<textarea v-model="form.bio" type="text" name="bio"
placeholder="Bio"
class="form-control" :class="{ 'is-invalid': form.errors.has('bio') }"></textarea>
<has-error :form="form" field="bio"></has-error>
</div>
<div class="form-group">
<select v-model="form.type" type="text" name="type"
class="form-control" :class="{ 'is-invalid': form.errors.has('type') }">
<option value="">Select user Role</option>
<option value="user">Employee</option>
<option value="manager">Manager</option>
</select>
<has-error :form="form" field="name"></has-error>
</div>
<div class="form-group">
<input v-model="form.password" type="password" name="password"
placeholder="password"
class="form-control" :class="{ 'is-invalid': form.errors.has('password') }">
<has-error :form="form" field="password"></has-error>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Create</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
users: {},
form: new Form({
name: '',
email: '',
password: '',
type: '',
bio: '',
photo: '',
})
}
},
methods: {
loadUsers() {
axios.get("api/user").then(({
data
}) => (this.user = data));
},
createUser() {
this.form.post('api/user');
}
},
created() {
this.loadUsers();
}
}
</script>
Please let me know if any other code is required for me to elaborate on the query that I have here. I have tried all options that I could think of and search and couldn't get it to work. Hopefully, another set of eyes can help me figure out the problem.
I expect a full table showing all the rows from my database, and the front-end shows nothing. (Note: I did check the network tab in the developer's options in Chrome and there was only a single xhr type and it showed status 200).
I suggest you go on youtube to search for laravel/vue tutorials, there are tons of good resources there that can help you.
For what you are trying to achieve, if you have mounted your component well and can see a dummy test in the component on your browser, then you are half way done.
Inside your mounted hook of your vue component, make an api call to your backend (laravel) to fetch users like so;
axios.get('/get_all_users').then((res)=>{
this.users = res.data
//do a console.log(res.data) to ensure you are getting the users collection
}).catch((err) => {
console.log(err)
});
Inside your data object, create an empty array that holds your users like so;
data(){
return{
users: []
}
}
Now, inside your web.php, create a GET route for this api call;
ROUTE::get('/get_all_users', 'UsersController#FetchUsers');
Note that your controller and method necessarily not be named as above, create a controller, and inside, write a method to fetch users and use them here asap;
Inside your controller, write your method;
public function FetchUsers(){
$users = User::latest()->get();
return response()->json($users, 200);
}
Also note that you will need to import your User model at the top of the controller file like so;
use App\User;
Also ensure before now that you have the User model created that relates to your users table;
By now you should see the arrays of users on your browser developer tool console if everything is fine.
Then in your template, iterate through the users data like so;
<tr v-for="user in users" :key="user.id">
<td>{{ user.id }} </td>
<td>{{ user.name }} </td>
<td>{{ user.email }} </td>
<td>{{ user.created_at }} </td>
</tr>
I will be glad to help in case you need further clarifications.
You need to return your data as json. You can use Laravel [Resource]
(https://laravel.com/docs/5.8/eloquent-resources)
Create user resource
php artisan make:resource User
User Controller
use App\Http\Resources\User as UserResource;
On your Method
$user = User::latest()->paginate(10);
return UserResource::collection($user)

Update data in array not rendering in DOM

On trying to update data in the array from the modal box. The data is not updated in the dom v-for list.
The following consists of modal and details. The data is entered in the modal box which updates the data in details. The cdata is an array which is updated through out the process. When the data is entered in the modal box. This data is pushed in the cdata. Which should update the details v-for loop but it is not happening rather. I tried updating by listening thru events still there's no effects.
data.vue
export default {
props: ["c-data"],
data: function() {
return {};
},
mounted: function() {},
methods: {}
};
<template>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#aModal">Add </button>
<data-detail :cdata="cData"></data-detail>
<add-modal :cdata="cData"></add-modal>
</template>
The following contains code for add modal which updates the data in cData array which is data entered in the data modal.
add-modal.vue
export default {
props: ["c-data"],
data: function() {
return {
cName: "",
cEmail: ""
};
},
mounted() {
console.log(this.cData);
},
methods: {
addC() {
this.cData.push({ cName: this.cName, cEmail: this.cEmail });
console.log(this.cData);
this.$root.$emit("cEvent", this.cData);
}
}
};
<template id="add-modal">
<div class="modal fade" id="aModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-large" role="document">
<div class="modal-content">
<div class="modal-body">
<div class="box">
<div class="row">
<div class="form-group col-sm-6 col-lg-6 col-xl-4">
<div class="input-section">
<input type="text" name="cName" class="form-control" id="c-name" v-model="cName" placeholder="Enter name" value="" required>
<label for="c-name"> Name*</label>
</div>
</div>
<div class="form-group col-sm-6 col-lg-6 col-xl-4">
<div class="input-section">
<input type="text" v-model="cEmail" name="cEmail" class="form-control" id="c-email" placeholder="Enter email" required>
<label for="c-email"> Email*</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-primary" data-dismiss="modal">Close</button>
<button type="button" #click="addC" class="btn btn-primary">Save</button>
</div>
</div>
</div>
</div>
</template>
The follow consists of list of v-for which needs to be updated but are not updating.
export default {
props: ["c-data"],
data: function() {
return {};
},
mounted() {
console.log(this.cData);
},
methods: {}
};
<div v-for="(item, i) in cData" :key="item.id">
{{item.name}}
</div>
I have tried to update it thru listening events but no results as cData was already update in the data component.
You should never directly manipulate data that is passed in as a property.
Using events was the right way to go, you just have to de-couple the newly added data from the properties object.
Use
this.$emit("cEvent", { name: this.cName, email: this.cEmail } );
And listen for it in the parent component
<add-modal :cdata="cData" #cEvent="handleNewData"></add-modal>
...
handleNewData(d) {
this.cData.push(d);
}
Your cData object should only be manipulated directly by the actual owner of that data i.e. the parent where the cData object originates from, not in any component where you pass it in as a property.
Full working example that you can use as a reference: https://codesandbox.io/s/n4lk7rmxx4

Advice/Opinion: Insert Data to a specific user using Firebase and Angular

I would really like some advice and opinion I am now currently inserting data from firebase using angular. I can now insert data but the problem is It won't insert inside the child I' am calling.
This is my task-form.component.html:
<form #t="ngForm" (ngSubmit)="add(t.value)">
<div class="form-group">
<label for="taskTechiciansName">Technicians Name</label>
<select ngModel name="taskTechniciansName" id="taskTechniciansName"
class="form-control">
<option value=""></option>
<option *ngFor="let a of techNames$ | async" [value] ="a.$key">
{{ a.name }}
</option>
</select>
</div>
<div class="form-group">
<label for="taskAdd">Address</label>
<input ngModel name="taskAdd" id="taskAdd" type="text" class="form-control">
</div>
<div class="form-group">
<label for="taskDate">Date</label>
<input ngModel name="taskDate" id="taskDate" type="date" class="form-control">
</div>
<div class="form-group">
<label for="taskClass">Class</label>
<input ngModel name="taskClass" id="taskClass" type="text" class="form-control">
</div>
<div class="form-group">
<label for="taskDesc">Description</label>
<input ngModel name="taskDesc" id="taskDesc" type="text" class="form-control">
</div>
<button class="btn btn-primary">Add Task</button>
</form>
here is my code tasks.service.ts:
import { Injectable } from '#angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { AngularFireAuthModule } from 'angularfire2/auth';
import { AngularFireDatabaseModule } from 'angularfire2/database';
#Injectable()
export class TaskService {
uid: string;
constructor(private db: AngularFireDatabase,
private af: AngularFireDatabase,
private am: AngularFireAuthModule
) {
}
create(tasks){
return this.db.database.ref('/users/').push({ tasks }).key;
}
}
and this is my database structure:
and this is how the data is being submitted:
task data
I really want to insert the info data into a specific user under tasks child. Your help is greatly appreciated.
The first mistake is a simple typo: you're missing a / in the path:
create(tasks){
return this.db.database.ref('/users/' + this.uid).push({ tasks }).key;
}
The second mistake is just as simple: you never give uid a value, so it's undefined. I'm just not sure how to fix it, since it depends on what you're trying to accomplish.

Ember app not posting to server with Ember Data

I am trying to connect my ember app to a node server on the backend. Right now, I have a sign up and login form and when the user submits either form it will go through an authentication process setup in node using Passport. However when the submit button is pressed it just reloads the current page and doesn't even send a HTTP post request. Any ideas on why this is happening/ how to fix it?
Here is my adapter:
import DS from "ember-data";
var ApplicationAdapter = DS.RESTAdapter.extend({
host: 'http://localhost:8080'
});
export default ApplicationAdapter;
Here is my sign up controller:
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
new: function() {
console.log('creating new user...');
var model = this.get('user');
user = this.get('store').createRecord('user', {
title: model.get('title'),
password: model.get('password')
});
user.save().then(function(data) {
// Clear the form.
Ember.$(':input').val('');
});
},
}
});
Here is my model:
import DS from 'ember-data';
export default DS.Model.extend({
username: DS.attr('string'),
password: DS.attr('string')
});
Here is the form:
<div class="row text-center">
<h1>Signup</h1>
</div>
<form>
<div class="row">
<div class="medium-6 medium-centered columns">
{{input value=username type="text" placeholder="Username"}}
</div>
</div>
<div class="row">
<div class="medium-6 medium-centered columns">
{{input value=password type="password" placeholder="Password"}}
</div>
</div>
<div class="row">
<div class="medium-6 medium-centered columns">
{{input class="button" type="submit" value="Signup"}}
</div>
</div>
</form>
Alright, so there seems to be a few issues here.
First, looking at the controller that you posted, there are a few things that don't look right:
The user variable is never declared
You try to get the user property from the controller, but it is never defined
You try to clear the form using Ember.$(':input').val(''); which doesn't really make any sense, if the inputs are bound to the template.
We'll start by cleaning up the template, which will drive the improvements to the controller:
<div class="row text-center">
<h1>Signup</h1>
</div>
<form>
<div class="row">
<div class="medium-6 medium-centered columns">
{{input value=username type="text" placeholder="Username"}}
</div>
</div>
<div class="row">
<div class="medium-6 medium-centered columns">
{{input value=password type="password" placeholder="Password"}}
</div>
</div>
<div class="row">
<div class="medium-6 medium-centered columns">
<button class="button" type="submit" {{action 'createUser'}}>Signup</button>
</div>
</div>
</form>
The major issues seems to be that you're using an {{input}} helper for the button, which doesn't really make any sense. The {{input}} helper if for inputting text. We've also moved the action to be bound to the button being clicked instead, which is the behavior that you want.
Now, the controller:
import Ember from 'ember';
export default Ember.Controller.extend({
// Username for the new user
username: '',
// Password for the new user
password: '',
actions: {
// Create a new user
createUser() {
const username = this.get('username');
const password = this.get('password');
this.get('store').createRecord('user', {
username,
password
}).save()
.then(() => {
this.send('clearForm'); // Invokes the `clearForm` action on the controller
})
.catch(() => {
// Do some kind of error handling if the creation fails
});
},
// Clear the form
clearForm() {
this.set('username', '');
this.set('password', '');
}
}
});
Now we have a controller with two properties defined, to hold the username and password for the new user. They are bound to the input fields in the template, and we manipulate them both get the values out of the template and also to clear them again.
You have a submit button that does a post request by default. You can do the following.
<form {{action 'new' on='submit'}}>
<div class="row">
<div class="medium-6 medium-centered columns">
{{input value=user.username type="text" placeholder="Username"}}
</div>
</div>
<div class="row">
<div class="medium-6 medium-centered columns">
{{input value=user.password type="password" placeholder="Password"}}
</div>
</div>
<div class="row">
<div class="medium-6 medium-centered columns">
<button class="button" type="submit">Signup</button>
</div>
</div>
</form>
This basically says intercept the submit event and call the action instead.
Note that I also added user. to your input values, otherwise you'd get them from your controller as this.get('username'), etc.

Categories