I am trying to make a very minimalistic form in AngularJS (version 1).
I am trying to use ng-model and the $scope to update an object I've named fluff. Once a user clicks submit it should be used in this $http call.
I'm highly confused I thought ng-model would bind this to the object in the scope. But it always returns a blank cause the $scope.fluff is not updating.
Yet if I inject {{ fluff.link }} this will update based on the textbox.
Here is my form in the view:
<form name="fluffForm" ng-submit="submitform()">
<span>Link: <input type="text" name="link" ng-model="form.link"></span>
<span>Description: <input type="text" name="description" ng-model="form.desc"></span>
<button type="submit">submit</button>
</form>
</div>
Here is my controller:
(function(){
'use strict';
angular.module('fluff').controller('FormController', FormController);
FormController.$inject = ['$scope', '$rootScope', '$routeParams', '$window', '$http'];
function FormController( $scope, $rootScope, $routeParams, $window, $http){
var form = this;
$scope.fluff = {}; // form data in json object(?) to be posted to mongo database
$scope.submitform = function(){
$scope.fluff.link = form.link;
$scope.fluff.description = form.desc;
console.log('form-data', $scope.fluff);
$http({
method: 'POST',
url: 'http://fluff.link/share',
data: $scope.fluff,
headers: {'Content-type': 'application/x-www-form-urlenconded'}
}).success(function(data){
console.log('Call to API was successful');
if(data.errors){
console.log('Data Errors');
console.log('error:', $data.errors.name);
//show errors - part of the response in the REST API have to make this portion up myself
$scope.errorName = $data.errors.name;
} else {
console.log('returned share id', data);
var fluff = 'fluff/link/'+ data;
$window.location.href = fluff;
}
});
}
}
})();
Here is my route:
(function(){
'use strict';
angular.module('fluff').config(Config);
Config.$inject = ['$routeProvider'];
function Config($routeProvider){
$routeProvider.when('/', {
templateUrl: 'views/index.client.view.html',
controller: 'FormController',
controllerAs: 'form'
});
}
})();
Added some logs from the developer console in chrome:
in submitform FormController {link: "test", desc: "test"}
fluff.form.controller.js:24 form-data Object {link: undefined}
Got it to work! Will update with my answer when it allows!
So my problem here is that I wasn't using the form controller like I should have.
Here I have the template being loaded with the controller as form.
$routeProvider.when('/', {
templateUrl: 'views/index.client.view.html',
controller: 'FormController',
controllerAs: 'form'
});
In the template I have to use form:
<span>Link: <input type="text" name="link" ng-model="form.link"></span>
<span>Description: <input type="text" name="description" ng-model="form.desc"></span>
then in the controller I create a this object:
var vm = this;
vm is now linked to form.
So now I can do this:
var fluff = {};
fluff.link = form.link;
fluff.description = form.desc;
Now fluff has all the data it needs when my user clicks submit.
Related
User is filling a form with different types of inputs.
On the same page he also can delete files from a server. After clicking a button a file is deleted, page is reloaded and changes made in other inputs are reset.
I've read a sessionStorage is something for me but currently I even have trouble injecting it. (Error: $injector:unpr Unknown Provider)
I think it delFile function in js controller it should be saving data to session storage, but how and where to retrieve it later?
jsp form:
<form ng-submit="save()">
<div>
Name:
<input type="text" ng-model="myForm.name" />
</div>
<div>
Type:
<select ng-model="myForm.type">
<option ng-selected="{{type.id == myForm.type}}" ng-repeat="type in types" value="{{type.id}}">{{type.description}}</option>
</select>
</div>
<div>
Is new:
<input type="checkbox" ng-model="myForm.isNew">
</div>
<div>
Files to upload:
<input type="file" file-input="filesToUpload" name="file" multiple />
<br>
Server files:
<p ng-repeat="serverFile in serverFiles" >
{{serverFile.name}}
<button type="button" ng-click="delFile(serverFile)">Delete from server</button>
</p>
</div>
<div>
<input type="submit" value="Save it!" />
</div>
</div>
</form>
js controller:
productApp.controller('ProductController', [
'$scope',
'$http',
'$log',
'$modal',
'$filter',
'$routeParams',
'$location',
'$window',
'$sessionStorage',
'productService',
function($scope, $http, $log, $modal, $filter, $routeParams, $location, $window, $sessionStorage, productService) {
$scope.productId= $routeParams.productId;
$scope.types= [];
$scope.myForm = {};
$scope.filesToUpload = [];
productService.getTypes().then(function(response) {
$scope.types = response.data;
});
productService.getServerFiles($scope.productId).then(function(response) {
$scope.serverFiles = response.data;
});
$scope.delFile = function(file) {
productService.deleteFileFromServer(file, $scope.productId);
// here it should be saving data to session storage I believe, but how and where to retrieve it later?
$window.location.reload();
};
$scope.save= function() {
$http({
method: 'POST',
url: '/product/app/save',
headers: {'Content-Type': undefined},
transformRequest: function (data) {
var formData = new FormData();
formData.append('myForm', new Blob([angular.toJson(data.myForm)], {
type: "application/json"
}));
for (var i = 0; i < $scope.filesToUpload.length; i++) {
$log.info("filesToUpload[i]: " + JSON.stringify($scope.filesToUpload[i]));
formData.append('files', $scope.filesToUpload[i]);
}
return formData;
},
data: {
myForm: $scope.myForm,
files: $scope.filesToUpload,
},
}).success(function(data) {
alert("All went well!");
$location.path('/inProgress');
}).error(function(data) {
$scope.$error = 'Error occurred!';
});
};
}
]);
SessionStorage is not an angular dependecy therefor you can not inject it.
If You really want you can create a service that wraps it and then inject service if you want to but it isn't necessary.
SessionStorage is a located on the window object which is global. Which means that you can reach it as such
sessionStorage.setItem("keyname", "YourValueAsString")
https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
Currently I have this component definition:
var controller = ['$http', '$timeout', '$scope', function($http, $timeout, $scope) {
this.isInvalid = function() {
return $scope.changePinForm.$invalid;
};
}];
var component = {
templateUrl: path.fromRoot('/application/libs/components/pin-change/view/pin-change.html'),
controller: controller,
controllerAs: 'vm'
};
angular.module('pin-change', ['confirm-reject', 'compare-validator', 'is-numeric'])
.component('pinChange', component);
});
Which references this html file via templateUrl:
<form name="changePinForm" class="form-horizontal">
<!-- etc. etc. -->
</form>
At the moment I am having to use scope to reference the form:
$scope.changePinForm.$invalid;
I would prefer to avoid scope and reference the form from the component's controller.
Is this possible or is scope still the only way?
You could make your form name to be name="vm.changePinForm" use vm(controller alias).
And then you can easily access vm.changePinForm.$invalid inside your controller. By which you aren't depending on $scope inside your controller.
var controller = ['$http', '$timeout',
function($http, $timeout) {
var vm = this;
vm.isInvalid = function() {
return vm.changePinForm.$invalid;
};
}
];
I am new to angularjs. I want to pass data from html form to another route.
Here is the part of index.html
<div ng-app="myApp" ng-controller="HomeController">
<div class="container">
<div class="row">
<div class="col-md-12">
<div ng-view=""></div>
</div>
</div>
</div>
</div>
Here are the routes
var myApp = angular.module('myApp', ['ngRoute']);
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'views/home.html',
controller: 'HomeController'
});
$routeProvider.when('/about', {
templateUrl: 'views/about.html',
controller: 'AboutController'
});
}]);
When the route is / it hits the views/home.html in which it has a form
<form action="#/about" ng-submit="submitData()">
<input type="text" name="address" ng-model="user.address" />
<input type="submit" />
</form>
I have a user service whose implementation is
myApp.factory("user", function () {
return {};
});
I inject user service in HomeController like
myApp.controller("HomeController", function ($scope, user) {
$scope.user = user;
// and then set values on the object
// $scope.user.address = "1, Mars"; // when uncomment this line it can be accessed on AboutController? Why? Otherwise I cannot access user.address
console.log($scope.user);
});
Don note my comment in above code..
and passes user to AboutController like
myApp.controller("AboutController", function ($scope, user) {
$scope.user = user;
// and then set values on the object
$scope.user.firstname = "John";
$scope.user.secondname = "Smith";
console.log($scope.user);
});
Here is the about.html
<p>
{{ user.address }}
</p>
Problem: {{user.address}} doesn't work on AboutController. I can't see any output... But when i remove the comment from above code.. It only displays hardcoded values in the controller What am I missing?
This is the working demo http://ashoo.com.au/angular/#/
At the moment, all your service does is pass a blank object return {}, to any controller into which it is injected. You need a getter/setter approach, so that in your Home view you can set the data, and in your About view you can retrieve it.
So your service could look something like this:
myApp.factory("user", function () {
var dataObj = {};
return {
setData: function(data) {
dataObj.username = data.username;
},
getData: function() {
return dataObj;
}
};
});
Now you can set the data in your Home controller:
myApp.controller("HomeController", function ($scope, user) {
$scope.submitData = function(data) { //pass in ng-model
user.setData(data); //call 'user' service to set data
}
});
And call it from your About controller:
myApp.controller("AboutController", function ($scope, user) {
$scope.user = user.getData(); //Assign
console.log($scope.user.username);
});
And you html would look like:
<form action="#/about" ng-submit="submitData(user.username)">
<input type="text" name="address" ng-model="user.username" />
<input type="submit" />
</form>
I have a question for all you AngularJs gurus out there. I am attempting to create modal wherein a user can submit files for upload. I have most of the problem sorted, however, I seem to be running into issues concerning scope. The technologies I am using are Angularjs, Angular UI Bootstrap and a custom file model directive.
I have a custom fileModel directive which on file selection updates the scope:
app.directive('fileModel', ['$parse', function($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function() {
scope.$apply(function() {
modelSetter(scope, element[0].files[0]);
});
});
}
}
}]);
I use UI bootstrap to create the modal as per the documentation (http://angular-ui.github.io/bootstrap/#/modal). Please note the file-model="file" directive in the input field, this is what I am trying to access.
<div ng-controller="ModalDemoCtrl">
// Button to open model
<button class="btn btn-default" data-ng-click="open()">Upload File</button>
// Simple Form in model
<script type="text/ng-template" id="myModalContent.html">
<form name="form.myForm" class="form-horizontal" data-ng-submit="addFile()" role="form" novalidate>
<div class="modal-header">
<h3 class="modal-title">Upload File</h3>
</div>
<div class="modal-body">
<div class="form-group">
<label for="file" class="col-sm-2 control-label">Input File</label>
<div class="col-sm-10">
<input type="file" name="file" file-model="file">
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-default">Submit</button>
</div>
</form>
</script>
</div>
Lastly I have the controller(s), again as per the Bootstrap UI documentation. Please note where I try to access $scope.file.
app.controller('ModalDemoCtrl', ['$scope', '$http', '$modal', function ($scope, $http, $modal) {
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
$http: function () {
return $http;
}
}
});
modalInstance.result.then(function () {
// do something
}, function () {
// do something
});
};
}]);
var ModalInstanceCtrl = function ($scope, $modalInstance, $http) {
$scope.addFile = function() {
var formData = new FormData();
formData.append('file', $scope.file);
$http.post(
'/valid/ajax/url', formData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).success(function(data, status, headers, config) {
// do something on success
});
);
};
I know there are some issues with regards to scope within modals when using angular UI bootstrap... unfortunately I am not experienced enough to find a solution. Currently, I am unable to access the file a user selects to be sent via ajax. Please help. Thanks.
I saw that the variable "$scope.file" is not being set, it stays undefined. Therefore you can't post the file. An easy way to share data between controllers (you have two, the modal controller and you parent controller) is using a service or factory. Check documentation if you are not sure. Then you can change the save the file via service/factory and use it in both controllers.
First of all the service which just contains a getter and a setter:
app.service('fileService', function () {
var file;
var fileService = {};
fileService.getFile = function () {
return file;
};
fileService.setFile = function (newFile) {
file = newFile;
};
return fileService;
});
You can then use the service via dependency injection on the directive and the controller:
app.directive('myFileUpload', function (fileService) {
return function (scope, element) {
element.bind('change', function () {
fileService.setFile(element[0].files[0]);
});
}
});
app.controller('ModalInstanceCtrl', function ($scope, $modalInstance, $http, fileService) {
$scope.addFile = function () {
var file = fileService.getFile();
console.log(file);
$http.post(
'http://posttestserver.com/post.php', file, {
transformRequest: angular.identity,
headers: {'Content-Type': file.type}
}).success(function (data, status, headers, config) {
console.log(data);
});
};
});
I created a fiddle so you can test it there. The file is outputted on the console. For testing the post I used http://posttestserver.com/post.php
http://jsfiddle.net/dz5FK/
I am trying to add some server side form validation to my angular js app. I'm having a hard time invalidating the form field and displaying the error message.
My basic application looks like this:
I have a model 'client' with a controler
Accounts.controller('Client', ['$scope', 'ClientService', function ($scope, ClientService) {
$scope.loading = false;
$scope.errors = null;
$scope.init = function () {
$scope.abn = "some value from API call";
};
$scope.save = function (client) {
$scope.form.abn.$setValidity("server", false);
$scope.errors.abn = "Error message";
}
$scope.init();
}]);
and a form view
<form name="form">
<div class="form-group">
<label>ABN Number</label>
<input type="text" name="abn" ng-model="client.abn">
<span ng-show="form.abn.$error.server">{{client.errors.abn}}</span>
</div>
<button ng-click="save(client)">Save</button>
</form>
and an app like so
var Accounts = angular.module('Accounts', [
'ngRoute',
'ui.select2',
'ui.router'
])
.config(function ($stateProvider, $routeProvider) {
$routeProvider.otherwise('/404');
$stateProvider
.state('client', {
url: "/client",
templateUrl: "client",
controller: 'Client'
})
.state('404', {
url: "/404",
templateUrl: "/error/e404/"
});
});
Is someone able to provide me with an example of how I should be setting the abn field as invalid and displaying an error message?
The way to display the error should be like this:
changed from $error.server to $invalid:
<span ng-show="form.abn.$invalid">{{client.errors.abn}}</span>
I added a style for ng-invalid class and created a plunkr where the field gets red and the errorMessage is displayed, once you press the save button. There was also another error when setting a property on $scope.errors because it was null.
http://plnkr.co/fDWF5g