How to access DOM from AngularJS controller? - angularjs

I am trying to submit a form from controller function in AngularJS. I need to do this without using jQuery because the target site
gives me a cross domain error when I use jQuery. I need to just post the form. Is it possible to do from controller without using jQuery?
I tried to use $element service but it seems to be jquery way of doing it and it is not really going to the target url.
Thank you for any suggestions.
<form name="myForm" id="myForm" method="post" action="#Model.Settings["URL"]" ng-controller="FormCtrl as fctrl">
</form>
setControllers.controller('FormCtrl', ['$scope', '$state', '$element', 'DataService',
function ($scope, $state, $element, service) {
var fctrl = this;
function init() {
$element.find('#myForm').submit();
};
init();
}]);

Well, you can totally do
function init() {
document.getElementById("myForm").submit();
};
but neither my solution, nor your approach are very angular-ish. You should probably go for some sort of directive.

Well. The angular way of submitting a form is by using ng-submit. Here's an example of how you can achieve it, in its simplest form, pun intended:
html
<html ng-app="FormModule">
<section ng-controller="formController as form">
<form ng-submit="form.submit()">
<label>Name</label>
<input ng-model="form.data.name" placeholder="Insert your name" />
<button type="submit">Submit My Name To The Server</button>
</form>
</section>
</html>
javascript
angular
.module('FormModule', [])
.controller('formController', formCtrl);
formCtrl.$inject = ['$scope']; // or whatever injection
function formCtrl($scope) {
var form = this;
form.data = {}; // ng-model form.data.name will be available in this
form.submit = submitTheForm;
function submitTheForm() {
$.post('url', form.data); // or whatever HTTP service you're using
}
}
Anyway, to help you understand and write better Angular code, here's how I learned writing better, and it is reflected in the code above
John Papa Angular 1.x Styleguide
ngSubmit Documentation

Related

How do i access a dynamically generated ng-model value of an input field using $scope.$watch in angularjs

I want to access a dynamically generated angular-ngmodel
value of an input field using $scope.$watch.
This is my code snippet below:
<body ng-app="myApp" ng-controller="myCtrl">
<form>
<input type="text" ng-model="<?php echo $product->id ?>" name="prid" />
<input type="submit" value="Add to Cart" ng-click="yea()"/>
</form>
</body>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.yea = function() {
$scope.$watch('xxx', function(){
var test = angular.copy($scope.xxx);
alert(test);
})
};
});
</script>
What I want to do actually: i want to get the dynamic generated value of
the text field above, then pass it through angularJS to a php variable.
So, I thought of the code above but got stucked (do not know what the xxx
wud be). Please, am I doing it the wrong way or is there any solution to
the code above?
Thanks
You could create your own directive:
<my-input my-input-id="{{'<?php echo $product->id ?>'}}"></my-input>
This way php should replace its code with the id, which you will then be able to use in your directive:
app.directive('myInput', function() {
return {
restrict: 'E',
scope: {
myInputId: '#'
},
template: '<input ng-model="myInputId" />'
};
});
Note that I haven't tested if this code really works. If you would create a plunkr or jsfiddle, I will be more than happy to take a look.
But I would personally never print out php in a way like this. Whenever I worked with PHP and Angular, I did HTTP calls from Angular to a PHP API. This way you have a clear separation between your Angular and PHP code.
You can use ngInit to initialize your model, like
<input type="text" ng-init="initPrid(<?php echo $product->id ?>)" ng-model="prId" name="prid" />
And then inside your controller add
$scope.initPrid = function(id) {
$scope.prId = id;
};

Angular typeahead not populating content

I have some serious troubles using typeahead in angular.js. The data is not populated even tough i can see in the function linked with the typehead attribute, that the objects are exiting
Relevant part of my controller:
angular.module('rechnungCtrl', ['rechnungService','kundeService'])
.controller('RechnungController', function(Rechnung, Kunde, $route, $routeParams, $location, $http) {
vm.searchKunde = function(val) {
Kunde.search(val)
.success(function(data) {
//When seting a breakpoint in chrome here i can see that the data is correctly loaded from the REST Service
return data;
});
}
Relevant part of my view:
<input type="text" class="form-control" id="kunde" placeholder="Kunde" typeahead="obj.vorname for obj in ctrl.searchKunde($viewValue)" ng-model="ctrl.selectedKunde">
Usage of the module
angular.module('EasyApp', ['ngBootbox', 'ui.bootstrap'])
And finally the relevant parts of index.html
<link href="app/views/bower_components/angular-bootstrap/ui-bootstrap-csp.css"></script>
<script src="app/views/bower_components/angular-bootstrap/ui-bootstrap.min.js"></script>
<script src="app/views/bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
I highly appreciate any help on this problem!!
BR,
Martin
The problem comes from the function vm.searchKunde. This function is not returning anything, therefore typeahead values are not populated. Try returning the promise, i.e. :
vm.searchKunde = function(val) {
return Kunde.search ...
}

AngularJS run function after scope is loaded

I have one form, that should be submitted with everage POST, without ajax. Just after it's rendering.
As it is an exclusion, I decided to use some jquery inside controller.
So my form:
<form name="Form" id="externalForm" action="{{form.url}}" method="POST" ng-controller="ExternalFormCtrl">
<input type="hidden" name="{{k}}" value="{{v}}" ng-repeat="(k, v) in form.form">
</form>
Amd my controller
app.controller('ExternalFormCtrl', ["$scope", "DataTransfer", function ($scope, DataTransfer) {
$scope.form = DataTransfer.get();
$('#externalForm').submit();
}]);
In DataTransfer I receive form with fields I need to send to external resource.
When it will render template, I want immidiatelly submit form with jquery.
How to submit form after rendering my form?
How to solve this task more ellegant, with angular way?
UPD: DataTransfer factory
app.factory('DataTransfer', [function() {
var savedData = {}
function set(data) {
savedData = data;
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
}]);
You could use vanilla javascript
document.getElementById('externalForm').submit();

pre-populated form data is undefined in service

jQuery:
$("#inputParentName").val(response.name);
HTML/Angular Form:
<form role="form" ng-submit="addParentService.addParent()">
<div class="form-group">
<label for="inputParentName">Name</label><input class="form-control" id="inputParentName" value="" type="text" ng-model="addParentService.inputParentName" />
</div>
...
<button class="btn btn-default" type="submit">Submit</button>
</form>
The following code when run diplays my name correctly in the input box.
However in my service when I try to see what the value is for inputParentName I get an undefined error. But, when I type something in to the textbox for inputParentName the typed in value displays.
Controller Code:
myapp.controller('AddParentController', function ($scope, addParentService) {
$scope.addParentService = addParentService;
});
Service Code:
myapp.service('addParentService', function () {
var vm = this;
vm.parent = [];
vm.addParent = function () {
alert(vm.inputParentName);
};
});
What can I do differently so I can get the pre-loaded data to register so that my service recognizes the data?
This is just basic code that I'm trying to get working. I realize it isn't pure AngularJS. I am just trying to see how I can get this to work. I will refactor with directives after everything works as I think it should.
If you want the initial value to be "something" when the view displays, you can (technically) use ng-init, though the docs tell us expressly NOT to do this.
The only appropriate use of ngInit is for aliasing special properties
of ngRepeat, as seen in the demo below. Besides this case, you should
use controllers rather than ngInit to initialize values on a scope.
But if you're just trying to test something, ng-init would look like:
<input ng-model="test.val" ng-init="test.val='something'" />
The preferred way though would be to add the value to the controller $scope.
<input ng-model="test.val" />
Then in your controller:
myapp.controller('MyCtrl', function ($scope) {
$scope.test = {
val: 'something'
}
});
#jme11 and This Answer gave me the insight to the following way I figured out how to get this to work:
jQuery code for Facebook logic:
$("#inputParentName").val(response.name);
$("#inputParentEmail").val(response.email);
$("#inputParentBirthday").val(response.birthday);
angular.element(document.getElementById('inputParentName')).scope().$apply();
angular.element($('#inputParentName')).scope().setName(response.name);
angular.element($('#inputParentEmail')).scope().setEmail(response.email);
angular.element($('#inputParentBirthday')).scope().setBirthday(response.birthday);
My Controller code:
$scope.setName = function (val) {
addParentService.inputParentName = val;
}
$scope.setEmail = function (val) {
addParentService.inputParentEmail = val;
}
$scope.setBirthday = function (val) {
addParentService.inputParentBirthday = val;
}
Service Code:
vm.addParent = function () {
alert(vm.inputParentName);
alert(vm.inputParentBirthday);
alert(vm.inputParentEmail);
alert(vm.inputParentCellPhone);
alert(vm.inputParentCarrier);
};
Now when I'm adding my Parent the values pre-populated from Facebook are usable in my service code.
Again - Thanks to jme11 for helping me solve this.

Dynamically add existing controller into another controller with AngularJS

in my app I have a wrapper controller that handles some properties dynamically based on other-controllers within it. everything works like a charm if the other-controllers are present/static on load, but as soon as I'm trying to make them dynamic, they stop working.
It was my understanding that the $rootScope is available from everywhere within the app, is that not true?
my JS looks like this:
var webApp = angular.module("webApp",[]);
webApp.controller("ControllerA", function($scope, $rootScope){
$rootScope.cnt = 0;
$rootScope.cntPlusPlus = function(){
$rootScope.cnt++;
};
$rootScope.controllerBs = [];
var template = $(".controller-b").html();
$scope.addControllerB = function(){
$rootScope.controllerBs.push(template);
};
});
webApp.controller("ControllerB", function($scope, $rootScope){
$scope.cntPlusPlus = function(){
console.log("overwrite plus plus");
}
});
Full example: http://plnkr.co/edit/tAcv1F9y7t9q9XsQ1EFL?p=preview
I know that this would be probably better with directives, but is there any way to make it work with Controllers?
thanks for the help
Don't try to access the DOM from controller code. Never. It is very bad practice which breaks AngularJS conventions and eventually provides you with bad architecture. This also means you should not create any DOM elements manually from a controller.
Better to manipulate with the scope itself, not with its visual representation. You can add new models to scope on your button's click, which will be translated to new elements by ng-repeat directive, each with its own controller (remember controllers are instances, not singletons, so that they have separated life cycles).
You might want to make use of <script type="text/ng-template"> and ng-include here instead of hidden divs.
Try to avoid using $rootScope when possible - it is global state which can be dangerous.
It might look like this then (plunker):
HTML:
<div class="controller-a" ng-controller="ControllerA">
Controller A
<div>
<button ng-click="cntPlusPlus()">cnt++</button> CNT: {{cnt}}
</div>
<button ng-click="addB()">Add B</button>
<div ng-repeat="B in Bs">
<div ng-include="'b-template'"></div>
</div>
</div>
<script type="text/ng-template" id="b-template">
<div ng-controller="ControllerB">this is controller b: <button ng-click="cntPlusPlus()">cnt++</button></div>
</script>
JS:
var webApp = angular.module("webApp",[]);
webApp.controller("ControllerA", function($scope){
$scope.cnt = 0;
$scope.cntPlusPlus = function(){
$scope.cnt++;
};
$scope.Bs = [];
$scope.addB = function(){
$scope.Bs.push({});
};
});
webApp.controller("ControllerB", function($scope){
$scope.cntPlusPlus = function(){
console.log("overwrite plus plus");
$scope.$parent.$parent.$parent.cnt++; //should be moved to service
}
});
</script>

Resources