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.
Related
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)
So I am trying to return a value from a text box as the parameter to another controller action that returns another partial. I think it would easier to just post some sample code rather than trying to explain what I am trying to do, so here is some sample code:
CSHTML:
<div class="row">
<div class="pt-sm-30 pb-xs-30 has-50px-footer">
<div class="col-lg-offset-1 col-lg-10">
<h3>CREATE A NEW PERSON PROFILE</h3>
<form class="form-spacers">
<div class="form-group">
<div class="row">
<div class="col-md-6">
<label class="input-label" for="functionalRole">First Name <span class="ReqField">*</span></label>
#Html.TextBoxFor(model => model.Person.FirstName, new { #class = "form-control input-sm", #id = "firstName", #type = "text" })
</div>
<div class="col-md-6">
<label class="input-label" for="functionalRole">Last Name <span class="ReqField">*</span></label>
#Html.TextBoxFor(model => model.Person.LastName, new { #class = "form-control input-sm", #id = "lastName", #type = "text" })
</div>
</div>
</div>
</form>
</div>
</div>
<div class="row">
<div class="col-sm-8 col-md-9 col-lg-10 new-profile-footer">
<div class="col-lg-offset-1 col-lg-5 col-md-4 hidden-sm hidden-xs" style="margin-top: 16px;">
</div>
<div class="col-lg-6 col-md-8 col-sm-12" style="margin-top: 10px; text-align: right;">
<div class="row" style="white-space: nowrap;">
<button class="btn btn-primary button-blue btn-xs-110" onclick="location.href='#Url.Action("Index", "DirectoryMaintainer")'"><i class="fa fa-times-circle-o icon-xs-hidden" aria-hidden="true" style="padding-right: 5px;"></i>CANCEL</button>
<button id="continue" type="button" class="btn btn-success button-green btn-xs-110">CONTINUE<i class="fa fa-caret-right icon-xs-hidden" style="padding-left: 5px;" aria-hidden="true"></i></button>
</div>
</div>
</div>
</div>
<script>
$("#continue").click(function () {
$("#partialViewDiv").load('#(Url.Action("RecordsMatch", "DirectoryMaintainer", new { #firstName = getFirstName(), #lastName = getLastName()}, Request.Url.Scheme))');
});
function getFirstName() {
return document.getElementById("firstName").value;
}
function getLastName() {
return document.getElementById("lastName").value;
}
</script>
Controller:
public PartialViewResult RecordsMatch(string firstName, string lastName)
{
//Do some logic with parameters here
return PartialView("_RecordsMatch");
}
So the issue I am having this that the line
$("#partialViewDiv").load('#(Url.Action("RecordsMatch", "DirectoryMaintainer", new { #firstName = getFirstName(), #lastName = getLastName()}, Request.Url.Scheme))');
is giving me an error on getFirstName() and getLastName(). The error is "The name getFirstName() does not exist in the current context". I am pretty new to MVC so I'm not sure if this is even possible or if there is a better way of doing it. If there is, then I am more than happy to learn it. Any and all suggestions would be greatly appreciated.
You cannot mix c# and js like that as the Url.Action gets executed in the server before your js code
Basically any C# code in your razor view gets executed by the razor view engine in the server and output of that (which is HTML/plain text) will be send to the browser. All your javascript code gets executed in the browser.
You can use Url.Action to generate the base url (without route value parameters) and add query strings to that at client side later.
$(function(){
$("#continue").click(function () {
var url='#Url.Action("RecordsMatch", "DirectoryMaintainer")';
url = url+'?firstName='+ getFirstName()+'&lastName='+getLastName();
$("#partialViewDiv").load(url);
});
});
When razor executes this code, it will render output like this (you can check the page view source and see this)
$(function(){
$("#continue").click(function () {
var url='/DirectoryMaintainer/RecordsMatch';
url = url+'?firstName='+ getFirstName()+'&lastName='+getLastName();
$("#partialViewDiv").load(url);
});
});
Using IronRouter, I have successfully rendered the page's template. I am trying to pass data from a collection to the unique page, but there is an error saying that the collection is not defined. Subscriptions aren't a problem since autopublish is installed.
I get the data from the form, store it, and then I want to display that data on the routed page.
So far, for the collection, I have:
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { Works } from '../api/works.js';
import './work.js';
import './body.html';
Template.main.helpers({
works() {
return Works.find({}, { sort: { createdAt: -1 } });
},
});
Template.main.events({
'submit .new-work'(event) {
event.preventDefault();
const title = event.target.title.value;
const workBriefDesc = event.target.workBriefDesc.value;
const workFullDesc = event.target.workFullDesc.value;
const workId = this._id;
Works.insert({
title,
workBriefDesc,
workFullDesc,
createdAt: new Date(),
owner: Meteor.userId(),
username: Meteor.user().username,
workId,
});
event.target.title.value = '';
event.target.workbriefdesc.value = '';
event.target.workfulldesc.value = '';
},
});
Template.collab.helpers({
works: function(){
return Works.findOne({_id:Router.current().params.workId});
},
});
And for the IronRouter file:
Router.route('/works/:_id', function () {
this.render('Collab');
}, {
name: 'collab',
data: function(){
return Works.findOne({ _id: this.params._id});
},
});
And the template file:
<!-- Publishing the template work -->
<template name="main">
<form class="new-work col s12">
<div class="row">
<div class="input-field col s6">
<input id="title" type="text" class="validate">
<label for="title">Name of work</label>
</div>
<div class="input-field col s6">
<select>
<option value="" selected>Choose category</option>
<option value="1">Prose</option>
</select>
<label></label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input id="workBriefDesc" type="text" length="250">
<label for="workBriefDesc">Brief description</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<textarea id="workFullDesc" class="materialize-textarea" length="10000"></textarea>
<label for="workFullDesc">Full description</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<textarea id="workessay" class="materialize-textarea"></textarea>
<label for="workessay">Essay</label>
</div>
</div>
<div class="modal-footer">
<button href="#!" class="modal-action modal-close waves-effect waves-grey btn-flat center" type="submit" name="action">Submit</button>
</div>
</form>
{{#each works}} {{ > work}} {{/each}}
</template>
<!-- Link to the unique page -->
<template name="work">
Go to work
</template>
<!-- Unique page attached to ID -->
<template name="collab">
{{title}} <br>
{{workBriefDesc}} <br>
{{workFullDesc}}
</template>
This is the error from the browser console:
Exception from Tracker recompute function:
meteor.js?hash=e3f53db…:930
ReferenceError: Works is not defined
at ctor.data (routes.js:17)
at Layout._data (iron_controller.js?hash=eb63ea9…:222)
at Layout.DynamicTemplate.data (iron_dynamic-template.js?hash=7644dc7…:215)
at iron_dynamic-template.js?hash=7644dc7…:248
at Blaze.View.<anonymous> (blaze.js?hash=983d07a…:2616)
at blaze.js?hash=983d07a…:1875
at Function.Template._withTemplateInstanceFunc (blaze.js?hash=983d07a…:3687)
at blaze.js?hash=983d07a…:1873
at Object.Blaze._withCurrentView (blaze.js?hash=983d07a…:2214)
at viewAutorun (blaze.js?hash=983d07a…:1872)
Added import { Works } from '/imports/api/works.js'; to my Router file.
I have a pretty big form that's being validated on the client side by Angular. I am trying to figure out how to reset the state of the form and its inputs just clicking on a Reset button.
I have tried $setPristine() on the form but it didn't really work, meaning that it doesn't clear the ng-* classes to reset the form to its original state with no validation performed.
Here's a short version of my form:
<form id="create" name="create" ng-submit="submitCreateForm()" class="form-horizontal" novalidate>
<div class="form-group">
<label for="name" class="col-md-3 control-label">Name</label>
<div class="col-md-9">
<input required type="text" ng-model="project.name" name="name" class="form-control">
<div ng-show="create.$submitted || create.name.$touched">
<span class="help-block" ng-show="create.name.$error.required">Name is required</span>
</div>
</div>
</div>
<div class="form-group">
<label for="lastName" class="col-md-3 control-label">Last name</label>
<div class="col-md-9">
<input required type="text" ng-model="project.lastName" name="lastName" class="form-control">
<div ng-show="create.$submitted || create.lastName.$touched">
<span class="help-block" ng-show="create.lastName.$error.required">Last name is required</span>
</div>
</div>
</div>
<button type="button" class="btn btn-default" ng-click="resetProject()">Reset</button>
</form>
And my reset function:
$scope.resetProject = function() {
$scope.project = {
state: "finished",
topic: "Home automation"
};
$("#create input[type='email']").val('');
$("#create input[type='date']").val('');
$scope.selectedState = $scope.project.state;
// $scope.create.$setPristine(); // doesn't work
}
Also if you could help me clear the input values of the email and date fields without using jQuery would be great. Because setting the $scope.project to what's defined above doesn't reset the fields for some reason.
Try to clear via ng-model
$scope.resetProject = function() {
$scope.project = {
state: "finished",
topic: "Home automation"
};
$("#create input[type='email']").val('');
$("#create input[type='date']").val('');
$scope.selectedState = $scope.project.state;
$scope.project = {
name: "",
lastName: ""
};
}
As mentioned in the comments, you can use $setUntouched();
https://docs.angularjs.org/api/ng/type/form.FormController#$setUntouched
This should set the form back to it's new state.
So in this case $scope.create.$setUntouched(); should do the trick
Ref all that jquery. You should never interact with the DOM via controllers. That's what the directives are for
If you want to reset a given property then do something like:
$scope.resetProject = function() {
$scope.project = {
state: "finished",
topic: "Home automation"
};
$scope.project.lastName = '';
$scope.project.date= '';
}
What I want to do is, make an ajax call whenever user stops entering something in the 'projectname' field & check it against database & show an kind of error message saying, "It exists". But the keypress event is not working as expected, first of all it omits the first letter entered & as a result word is not sent to database completely.
Here's my Controller:
App.ProjectController = Ember.ArrayController.extend({
actions : {
createNew : function() {
data = {
projectname : this.get('projectname'),
projectdesc : this.get('projectdesc'),
projectbudget : this.get('projectbudget'),
};
console.log(JSON.stringify(data));
//console.log(id);
$.ajax({
type : "POST",
url : "http://ankur.local/users/createNewProject",
data : data,
dataType : "json",
success : function(data) {
console.log('success');
//alert('');
}
});
alertify.success("Project Created");
this.set('projectname', "");
this.set('projectdesc', "");
this.set('projectbudget', "")
return false;
},
checkName: function(){
data = {
projectname : this.get('projectname'),
};
var checkedName = $.ajax({
type : "POST",
url : "http://ankur.local/users/checkProjectName",
data : data,
dataType : "json",
success : function(data) {
console.log('Yes it');
}
});
console.log(data);
console.log(checkedName);
}
}
});
and Here's the HTML,
<script type="text/x-handlebars" id="project">
<div class="row" style="padding-left: 30px">
<div class="span12" id="form-container">
<div class="well well-small">
<p style="text-align: center">
You can create a new Project by filling this simple form.
</p>
<p style="text-align: center"> Project Name should be minimum 10 characters & maximum 50 characters.
Project Description
10 to 300 characters.
</p>
</div>
<div class="row" id="test">
<div class="offset3 span8">
<form class="form-horizontal" id="projectform">
<div class="control-group">
<label class="control-label" for="projectname">Project Name: </label>
<div class="controls">
{{view Ember.TextField valueBinding='projectname' style="max-width: 100%" onEvent="keyUp" action=checkName}}
</div>
</div>
<div class="control-group">
<label class="control-label" for="projectdesc">Project Description:</label>
<div class="controls">
{{view Ember.TextArea valueBinding='projectdesc' style="max-width: 100%"}}
</div>
</div>
<div class="control-group">
<label class="control-label" for="projectbudget">Project Budget($)</label>
<div class="controls">
{{view Ember.TextField valueBinding='projectbudget' id="budget" style="max-width: 100%"}}
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn"
{{action 'createNew' }}>Add Project</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
What improvements I can make to achieve the desired result?
Key press is working as expected, key press happens before the textbox value has changed.
It looks like key up isn't supported in the manner that you want tho. Fortunately it's really easy to override:
App.KeyUpTextField = Em.TextField.extend({
keyUp:function(event){
this.sendAction('upKeyAction', event);
}
});
{{view App.KeyUpTextField value=projectname upKeyAction='checkName'}}
BTW I'd do debounce or something like that in your keyUp function, it seems like it'd get a bit chatty to send the request on every keyup event.