I have a problem with a form implemented using Angular.
defining my variable in the scope I can see value (pre-filled) in the html form (ng-model), but when I submit the function, the new data (inserted by the users) don't update the model ($scope var) in the controller.
Here a snipped of my html and js controller:
<form class="form-horizontal">
<h3>Citizen</h3>
<div class="row">
<div class="form-group">
<label for="name" class="col-sm-2 control-label">Name</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="name" ng-model="ticketDetails.ticketDetails.name" placeholder="Name">
</div>
<label for="DOB" class="col-sm-2 control-label">Birth date</label>
<div class="col-sm-4">
<input type="date" class="form-control" id="DOB" ng-model="ticketDetails.ticketDetails.DOB" placeholder="Birth Date">
</div>
</div>
</div>...
and the controller
angular.module('demoApp', [])
.controller('mainController', function($scope, $http) {
// $scope.ticketDetails = { "ticketDetails" : {
// "name": "Giovanni Vigorelli",
// "DOB": "1974-05-02T05:07:13Z",
// "driverLicense": "e345234",
// "registration": "hdd843",
// "ticketType": "Speeding",
// "date": "2016-05-02T05:07:13Z",
// "location": "34 Queen St, Auckland",
// "ticketId": "12345",
// "officer": "Oscar Nice"
// }};
$scope.ticketDetails = { "ticketDetails": {}};
$scope.ticketDetails.ticketDetails.ticketId = (+new Date).toString(36).slice(-5);
// The following should be the authentucated user
$scope.ticketDetails.ticketDetails.officer = "Oscar Nice";
var bpmQueryParam = 'action=start&bpdId=25.c1206b63-1e94-4aaa-9dc1-76363270b441&processAppId=2066.d0e91cc6-a515-4965-ba6f-516bdbddcb00¶ms=' + JSON.stringify($scope.ticketDetails) + '&parts=all';
$scope.startProcess = function(){
console.log('### In startProcess');
console.log("### bpmQueryParam: " + bpmQueryParam);
var req = {
method: 'POST',
headers: {'Authorization': 'Basic YWRtaW46YWRtaW4=','Accept': 'application/json','Access-Control-Allow-Origin': '*', 'Content-Type': 'application/x-www-form-urlencoded'},
url: 'http://1.1.1.1:9080/rest/bpm/wle/v1/process',
data: bpmQueryParam
}
Basically I don't a bidirectional sync of the var, just from controller to view and NOT from view to controller.
Any advice?
Cheers, Giovanni
I suppose $scope.startProcess is your submit function. Please write the following line inside the submit function:
var bpmQueryParam = 'action=start&bpdId=25.c1206b63-1e94-4aaa-9dc1-76363270b441&processAppId=2066.d0e91cc6-a515-4965-ba6f-516bdbddcb00¶ms=' + JSON.stringify($scope.ticketDetails) + '&parts=all';
You have wriiten this code outside the function, therefore it is taking the initial data for $scope.ticketDetails variable.
You should write it as following:
$scope.startProcess = function(){
var bpmQueryParam = 'action=start&bpdId=25.c1206b63-1e94-4aaa-9dc1-76363270b441&processAppId=2066.d0e91cc6-a515-4965-ba6f-516bdbddcb00¶ms=' + JSON.stringify($scope.ticketDetails) + '&parts=all';
// Rest of your code
}
Related
When I select one of the cards on the page below, I wish to have the value of the inputs updated with values from a JSON object
The json:
{
"status": true,
"data": [
{
"id": 1,
"pessoa_id": 75505,
"created_at": "2022-02-01T17: 42: 46.000000Z",
"holder": "LEONARDO LIMA",
"validade": "2026-06-01",
"bandeira": "Mastercard"
}
]
}
The json value is on the variable "responseData"
renderTokenCard() {
this.mundipaggS.checkToken().subscribe((response: any) => {
console.log(JSON.stringify(response));
this.cartS.tokenCard = response;
this.responseData = response;
console.log(JSON.parse(JSON.stringify(response)));
},);
}
the function that is linked to the select action:
SelecionarCartao() {
this.mundipaggS.postToken(this.responseData)
console.log(this.responseData)
}
I wanted to get the responseData value and make a post for the postToken
The HTML
<div class="form-group ">
<label for="ncartao">Número do cartão <span class="text-danger"> *</span></label>
<input name="card-number" maxlength="19" #cardNumber formControlName="digiNumero" id="ncartao" type="text"
class="form-control col-lg-6 ">
</div>
<div class="form-group">
<label for="nomeimpresso">Nome <b>impresso</b> no cartão<span class="text-danger"> *</span></label>
<input #nomeImpresso formControlName="digiNome" name="holder-name" id="nomeimpresso" class="form-control col-lg-6"
type="text">
</div>
"Think in functions". If you has a function like
getGroup(data:any=null)
{
//data will be the properties by defect and, using spread operator,
//replace the properties by the data object
data={
id: 0,
pessoa_id:0,
created_at:"",
holder: "",
validade: "",
bandeira:"",
...data
}
return new FormGroup({
id: new FormControl(data.id),
pessoa_id: new FormControl(data.pessoa_id),
created_at:new FormControl(data.created_at),,
holder: new FormControl(data.holder),,
validade: new FormControl(data.validade),,
bandeira:new FormControl(data.bandeira),}
})
}
Each change in "Meus Cartoes"
change(bandeira:string)
{
const data=this.responseData.data.find(x=>x.bandeira==bandeira)
if (data)
this.form=getGroup(data) //<--a form with all the data
else
this.form=getGroup({bandeira:bandeira}) //<--a form with the "bandeira"
}
NOTE: really the "form" need split the "validate", get the "numero do cartao" and the "nome_impreso"...
I am doing an exercise of an online course. In this exercise I have a form with 3 inputs and I have to extract them to make a request to a server. My problem is that my JavaScript Code only returns the empty string if I log it in the console, not the changed value. I guess it's accessing the inital value of the html. How can I solve this?
JavaScript Code:
// Initial call if the form is submitted
document.querySelector("#compose-submit").onsubmit = send_mail();
// The send_mail function:
function send_mail() {
let recipients = document.querySelector('#compose-recipients').value; // Those return the empty string,
let subject = document.querySelector("#compose-subject").value; // although something was written
let body = document.querySelector("#compose-body").value; // inside
fetch("/emails", {
method: "POST",
body: JSON.stringify({
recipients: recipients,
subject: subject,
body: body
})
})
.then(response => response.json())
.then(result => {
console.log(result);
});
return false;
Corresponding html:
<h3>New Email</h3>
<form id="compose-form">
<div class="form-group">
From: <input disabled class="form-control" value="{{ request.user.email }}">
</div>
<div class="form-group">
To: <input id="compose-recipients" class="form-control">
</div>
<div class="form-group">
<input class="form-control" id="compose-subject" placeholder="Subject">
</div>
<textarea class="form-control" id="compose-body" placeholder="Body"></textarea>
<input type="submit" class="btn btn-primary" id="compose-submit"/>
</form>
In the first line when you are assigning a callback to the onsubmit event, you need to just pass the function name and not call it.
So, changing your first line of code to
document.querySelector("#compose-submit").onclick = send_mail;
or
bind your event to the form element to make it work with onsumbit event
document.querySelector("#compose-form").onsubmit = send_mail;
should work.
Here's a JSFiddle as a sample (check console)
Change your input type to button to prevent reloading the page after submitting. And you will keep your values
// Initial call if the form is submitted
document.querySelector("#compose-submit").addEventListener('click', () => {
send_mail();
});
// The send_mail function:
function send_mail() {
let recipients = document.querySelector('#compose-recipients').value; // Those return the empty string,
let subject = document.querySelector("#compose-subject").value; // although something was written
let body = document.querySelector("#compose-body").value; // inside
console.log(recipients);
console.log(subject);
console.log(body);
fetch("/emails", {
method: "POST",
body: JSON.stringify({
recipients: recipients,
subject: subject,
body: body
})
})
.then(response => response.json())
.then(result => {
console.log(result);
});
return false;
}
<h3>New Email</h3>
<form id="compose-form">
<div class="form-group">
From: <input disabled class="form-control" value="{{ request.user.email }}">
</div>
<div class="form-group">
To: <input id="compose-recipients" class="form-control">
</div>
<div class="form-group">
<input class="form-control" id="compose-subject" placeholder="Subject">
</div>
<textarea class="form-control" id="compose-body" placeholder="Body"></textarea>
<input type="button" value="Submit" class="btn btn-primary" id="compose-submit" />
</form>
It's because of the submit type, when you submit the form, it submits the values of the form to the given url path of your action attribute of the form <form action="path_to_fetch" method="POST"> and then refreshed the page after. So your javascript code can't catch the values of the form.
One solution is to prevent the form to be refreshed and let your javascript code do the fetching method.
so in your js code, do this:
// Initial call if the form is submitted
document.querySelector("#compose-submit").addEventListener("click", send_mail);
// The send_mail function:
function send_mail(e) {
let recipients = document.querySelector('#compose-recipients').value; // Those return the empty string,
let subject = document.querySelector("#compose-subject").value; // although something was written
let body = document.querySelector("#compose-body").value; // inside
fetch("/emails", {
method: "POST",
body: JSON.stringify({
recipients: recipients,
subject: subject,
body: body
})
})
.then(response => response.json())
.then(result => {
console.log(result);
}).finally(() => {
document.querySelector('#compose-recipients').value = "";
document.querySelector("#compose-subject").value = "";
document.querySelector("#compose-body").value = "";
})
}
Use the finally function to empty the form after submitting the form.
EDIT:
And also change your button type to just button, using the submit type will cause the refresh.
<button class="btn btn-primary" id="compose-submit" type="button">Submit</button>
I'm using mean.js to create a system and I change the mongoose part for sequelize and I trying to save multiple Objects from Angular to my database through sequelize.
I followed this answer to create multiple inputs dynamically on the Dia (Day) option for multiple schedules.
And I have my controller like this:
$scope.horarios = [];
$scope.itemsToAdd = [{
Day: '',
StartHour: '',
EndHour: ''
}];
$scope.add = function(itemToAdd) {
var index = $scope.itemsToAdd.indexOf(itemToAdd);
$scope.itemsToAdd.splice(index, 1);
$scope.horarios.push(angular.copy(itemToAdd))
};
$scope.addNew = function() {
$scope.itemsToAdd.push({
Day: '',
StartHour: '',
EndHour: ''
});
console.log($scope.itemsToAdd);
};
and view
<div class="col-xs-12" style="padding: 0" ng-repeat="itemToAdd in itemsToAdd">
<div class="form-group col-xs-12 col-sm-5" >
<label for="Days">Dia</label> <select class="form-control col-xs-12 col-sm-6" data-ng-model="itemToAdd.Day" id="Days" name="Days">
<option value="">---Seleccione uno---</option>
....
</select>
</div>
<div class="form-group col-xs-5 col-sm-3">
<label class="control-label" for="startHour">Hora Inicio</label> <input class="form-control" id="startHour" name="startHour" ng-model="itemToAdd.StartHour" type="time">
</div>
<div class="form-group col-xs-5 col-sm-3">
<label class="control-label" for="endHour">Hora Termino</label> <input class="form-control" id="endHour" name="endHour" ng-model="itemToAdd.EndHour" type="time">
</div>
<div class="col-xs-2 col-sm-1">
<button ng-click="addNew()" class="btn btn-success" style="position: relative; top:26px"><i class="glyphicon glyphicon-plus"></i></button>
</div>
</div>
Then I have my both controllers on client side with Angular:
// Create new course
$scope.create = function( isValid ) {
// Create new course object
var course = new Courses( $scope.course );
course.Schedule = $scope.itemsToAdd;
console.log($scope.course);
// Redirect after save
course.$save( function( response ) {
$scope.closeThisDialog();
notify( 'Genial. El Curso ha sido registrada exitosamente' );
// Clear form fields
$scope.course = '';
$scope.schedule = '';
}, function( errorResponse ) {
$scope.error = errorResponse.data.message;
} );
};
And sequelize:
exports.create = function(req, res) {
var schedule = req.body.Schedule;
req.body.schedule = undefined;
// req.body.userId = req.user.id;
db.Course.create(req.body)
.then(function(course) {
if (!course) {
return res.send('users/signup', {
errors: 'Could not create the course'
});
} else {
schedule.CourseId = course.dataValues.id;
db.Schedule.create(schedule)
.then(function(schedule) {
for (var i = schedule.dataValues.length - 1; i >= 0; i++) {
course.schedule = schedule.dataValues[i];
}
// course.schedule = schedule.dataValues;
})
.catch(function(err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
});
return res.jsonp(course);
}
})
.catch(function(err) {
return res.status(400)
.send({
message: errorHandler.getErrorMessage(err)
});
});
};
But honestly I don't have a clue how to save it or if my Angular controller is even the correct way to do it. Hope you can help me or give me hint how to do it.
In addition to updating a single instance, you can also create, update, and delete multiple instances at once. The functions you are looking for are called
Model.bulkCreat
http://docs.sequelizejs.com/en/2.0/docs/instances/#working-in-bulk-creating-updating-and-destroying-multiple-rows-at-once
I have been searching for a long while for solution, but nothing helped me.
I have an Angular JS app which runs with Mongoose and Express.
I want to store date as object from a simple form.
But when I submit my form, dates are stored as String and not as Objects.
So I can't do something like :
tache.start.getDate();
Here is my form :
<form name="formTache" ng-submit="addTache(tache)">
<div class="form-group row">
<div class="col-lg-12">
<input name="name" class="form-control" placeholder="Nom" type="text" ng-model="tache.title"/>
</div>
</div>
<div class="form-group row">
<div class="col-lg-12">
<input id="date" name="date" class="form-control" placeholder="Date" ng-model="tache.start" type="date"/>
</div>
</div>
<div class="form-group row">
<div class="text-right col-lg-12">
<button type="submit" class="btn btn-default">Ajouter</button>
</div>
</div>
Here is my Mongoose Schema :
var restful = require('node-restful');
var mongoose = restful.mongoose;
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var tachesSchema = new mongoose.Schema({
title : String,
start: {type: Date, default: new Date()},
});
var tachesModel = mongoose.model('taches', tachesSchema);
module.exports = restful.model('taches', tachesSchema);
Here is my Controller :
angular.module('personaldashboard.tache', [])
.controller('TachesCtrl', function($scope, Taches, Progress, toaster) {
$scope.tache = new Taches();
var refreshTache = function() {
$scope.taches = Taches.query();
$scope.tache = ''
}
refreshTache();
$scope.addTache = function(tache) {
Taches.save(tache,function(tache){
refreshTache();
});
};
$scope.updateTache = function(tache) {
tache.$update(function(){
refreshTache();
});
};
$scope.removeTache = function(tache) {
tache.$delete(function(){
refreshTache();
});
};
$scope.editTache = function(id) {
$scope.tache = Taches.get({ id: id });
};
$scope.deselectTache = function() {
$scope.tache = ''
}
$scope.editTache_Projet = function(tache, projetId) {
tache.projet = projetId;
tache.$update(function(){
refreshTache();
});
};
});
Here is what I get :
{ "_id": "58a99df24975ad0104c692b1", "title": "Test", "start": "2017-02-24T23:00:00.000Z" }
So why do I get a string like "2017-02-24T23:00:00.000Z" for my date instead of an object whereas my Mongoose schema specify start: {type: Date, default: new Date()} ?
Thanks for your help.
EDIT
Thanks to Saurabh Agrawal, I tried to convert the date when submiting in the controller :
$scope.addTache = function(tache) {
tache.start = new Date(tache.start);
tache.end = new Date(tache.end);
Taches.save(tache,function(tache){
refreshTache();
});
};
Sadly, this changed nothing :(
I still have a date as string
"2017-02-20T23:00:00.000Z"
EDIT
I also tried to add a directive
.directive("formatDate", function(){
return {
scope: {ngModel:'='},
link: function(scope) {
if (scope.ngModel) {
scope.ngModel = new Date(scope.ngModel);
}
}
}
})
and call it in my form
<form name="formTache" ng-submit="addTache(tache)">
<div class="form-group row">
<div class="col-lg-12">
<input name="name" class="form-control" placeholder="Nom" type="text" ng-model="tache.title"/>
</div>
</div>
<div class="form-group row">
<div class="col-lg-12">
<input id="date" name="date" class="form-control" placeholder="Date" ng-model="tache.start" type="date" formatDate/>
</div>
</div>
<div class="form-group row">
<div class="text-right col-lg-12">
<button type="submit" class="btn btn-default">Ajouter</button>
</div>
</div>
But nothing changes.
Any other ideas ?
By searching, I 've found that I was missing the real problem.
My dates are date objects.
When i do this
$scope.test = new Date([2017,2,15]);
<pre>{{test}}</pre>
<pre>{{test.getDate()}}</pre>
I get
"2017-02-14T23:00:00.000Z" and 15
So date displaying like "2017-02-14T23:00:00.000Z" are objects.
But in my case, when i try to do the same with a date whitch is in another object like in this schema :
var tachesSchema = new mongoose.Schema({
title : String,
start: {type: Date, default: new Date()},
end: {type: Date, default: new Date()},
comment : String,
state : Boolean,
projet : { type: ObjectId, ref: 'Projets' }
});
I get nothing :(
This code :
{{tache.start}}
displays the date like this "2017-02-20T23:00:00.000Z"
but
<pre>{{tache.start.getDate()}}</pre>
displays nothing.
What I missed ?
I'm a beginner to angular.js but I have a good grasp of the basics.
What I am looking to do is upload a file and some form data as multipart form data. I read that this isn't a feature of angular, however 3rd party libraries can get this done. I've cloned angular-file-upload via git, however I am still unable to post a simple form and a file.
Can someone please provide an example, html and js of how to do this?
First of all
You don't need any special changes in the structure. I mean: html input tags.
<input accept="image/*" name="file" ng-value="fileToUpload"
value="{{fileToUpload}}" file-model="fileToUpload"
set-file-data="fileToUpload = value;"
type="file" id="my_file" />
1.2 create own directive,
.directive("fileModel",function() {
return {
restrict: 'EA',
scope: {
setFileData: "&"
},
link: function(scope, ele, attrs) {
ele.on('change', function() {
scope.$apply(function() {
var val = ele[0].files[0];
scope.setFileData({ value: val });
});
});
}
}
})
In module with $httpProvider add dependency like ( Accept, Content-Type etc) with multipart/form-data. (Suggestion would be, accept response in json format)
For e.g:
$httpProvider.defaults.headers.post['Accept'] = 'application/json, text/javascript';
$httpProvider.defaults.headers.post['Content-Type'] = 'multipart/form-data; charset=utf-8';
Then create separate function in controller to handle form submit call.
like for e.g below code:
In service function handle "responseType" param purposely so that server should not throw "byteerror".
transformRequest, to modify request format with attached identity.
withCredentials : false, for HTTP authentication information.
in controller:
// code this accordingly, so that your file object
// will be picked up in service call below.
fileUpload.uploadFileToUrl(file);
in service:
.service('fileUpload', ['$http', 'ajaxService',
function($http, ajaxService) {
this.uploadFileToUrl = function(data) {
var data = {}; //file object
var fd = new FormData();
fd.append('file', data.file);
$http.post("endpoint server path to whom sending file", fd, {
withCredentials: false,
headers: {
'Content-Type': undefined
},
transformRequest: angular.identity,
params: {
fd
},
responseType: "arraybuffer"
})
.then(function(response) {
var data = response.data;
var status = response.status;
console.log(data);
if (status == 200 || status == 202) //do whatever in success
else // handle error in else if needed
})
.catch(function(error) {
console.log(error.status);
// handle else calls
});
}
}
}])
<script src="//unpkg.com/angular/angular.js"></script>
This is pretty must just a copy of that projects demo page and shows uploading a single file on form submit with upload progress.
(function (angular) {
'use strict';
angular.module('uploadModule', [])
.controller('uploadCtrl', [
'$scope',
'$upload',
function ($scope, $upload) {
$scope.model = {};
$scope.selectedFile = [];
$scope.uploadProgress = 0;
$scope.uploadFile = function () {
var file = $scope.selectedFile[0];
$scope.upload = $upload.upload({
url: 'api/upload',
method: 'POST',
data: angular.toJson($scope.model),
file: file
}).progress(function (evt) {
$scope.uploadProgress = parseInt(100.0 * evt.loaded / evt.total, 10);
}).success(function (data) {
//do something
});
};
$scope.onFileSelect = function ($files) {
$scope.uploadProgress = 0;
$scope.selectedFile = $files;
};
}
])
.directive('progressBar', [
function () {
return {
link: function ($scope, el, attrs) {
$scope.$watch(attrs.progressBar, function (newValue) {
el.css('width', newValue.toString() + '%');
});
}
};
}
]);
}(angular));
HTML
<form ng-submit="uploadFile()">
<div class="row">
<div class="col-md-12">
<input type="text" ng-model="model.fileDescription" />
<input type="number" ng-model="model.rating" />
<input type="checkbox" ng-model="model.isAGoodFile" />
<input type="file" ng-file-select="onFileSelect($files)">
<div class="progress" style="margin-top: 20px;">
<div class="progress-bar" progress-bar="uploadProgress" role="progressbar">
<span ng-bind="uploadProgress"></span>
<span>%</span>
</div>
</div>
<button button type="submit" class="btn btn-default btn-lg">
<i class="fa fa-cloud-upload"></i>
<span>Upload File</span>
</button>
</div>
</div>
</form>
EDIT: Added passing a model up to the server in the file post.
The form data in the input elements would be sent in the data property of the post and be available as normal form values.
It is more efficient to send the files directly.
The base64 encoding of Content-Type: multipart/form-data adds an extra 33% overhead. If the server supports it, it is more efficient to send the files directly:
Doing Multiple $http.post Requests Directly from a FileList
$scope.upload = function(url, fileList) {
var config = {
headers: { 'Content-Type': undefined },
transformResponse: angular.identity
};
var promises = fileList.map(function(file) {
return $http.post(url, file, config);
});
return $q.all(promises);
};
When sending a POST with a File object, it is important to set 'Content-Type': undefined. The XHR send method will then detect the File object and automatically set the content type.
Working Demo of "select-ng-files" Directive that Works with ng-model1
The <input type=file> element does not by default work with the ng-model directive. It needs a custom directive:
angular.module("app",[]);
angular.module("app").directive("selectNgFiles", function() {
return {
require: "ngModel",
link: function postLink(scope,elem,attrs,ngModel) {
elem.on("change", function(e) {
var files = elem[0].files;
ngModel.$setViewValue(files);
})
}
}
});
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<h1>AngularJS Input `type=file` Demo</h1>
<input type="file" select-ng-files ng-model="fileList" multiple>
<h2>Files</h2>
<div ng-repeat="file in fileList">
{{file.name}}
</div>
</body>
You can check out this method for sending image and form data altogether
<div class="form-group ml-5 mt-4" ng-app="myApp" ng-controller="myCtrl">
<label for="image_name">Image Name:</label>
<input type="text" placeholder="Image name" ng-model="fileName" class="form-control" required>
<br>
<br>
<input id="file_src" type="file" accept="image/jpeg" file-input="files" >
<br>
{{file_name}}
<img class="rounded mt-2 mb-2 " id="prvw_img" width="150" height="100" >
<hr>
<button class="btn btn-info" ng-click="uploadFile()">Upload</button>
<br>
<div ng-show = "IsVisible" class="alert alert-info w-100 shadow mt-2" role="alert">
<strong> {{response_msg}} </strong>
</div>
<div class="alert alert-danger " id="filealert"> <strong> File Size should be less than 4 MB </strong></div>
</div>
Angular JS Code
var app = angular.module("myApp", []);
app.directive("fileInput", function($parse){
return{
link: function($scope, element, attrs){
element.on("change", function(event){
var files = event.target.files;
$parse(attrs.fileInput).assign($scope, element[0].files);
$scope.$apply();
});
}
}
});
app.controller("myCtrl", function($scope, $http){
$scope.IsVisible = false;
$scope.uploadFile = function(){
var form_data = new FormData();
angular.forEach($scope.files, function(file){
form_data.append('file', file); //form file
form_data.append('file_Name',$scope.fileName); //form text data
});
$http.post('upload.php', form_data,
{
//'file_Name':$scope.file_name;
transformRequest: angular.identity,
headers: {'Content-Type': undefined,'Process-Data': false}
}).success(function(response){
$scope.IsVisible = $scope.IsVisible = true;
$scope.response_msg=response;
// alert(response);
// $scope.select();
});
}
});