AngularJs watch angular.element - angularjs

I'm trying to integrate AngularJs into a legacy Spring MVC application because there is lots of spaghetti javascript code (a huge mess!) to hide / show html elements based on conditions etc.
It uses jsp and lots of custom jsp tags and because the way it is written I'm hesitant to mess with the jsp tags themselves.
I'm trying to do is read the values of the spring input into angular scope and once I have it then can use angular to hide / show stuff.
Assume that my html is something like this
<div ng-app ng-controller="FooCtrl">
Backbone <input type="radio" name="yes" value="Backbone"/>
Angular <input type="radio" name="yes" value="Angular" />
</div>
I'm able to read these elements into Angular's scope like this
$scope.elements = angular.element("input[name='yes']");
But change to the value of these elements are not getting triggered or watched by Angular.
Ideally when the radio button gets checked I would like the model to change. How can I do this?
Thank you in advance.
Here is plnkr with the basic setup.
http://plnkr.co/edit/CRPBFF9FaGivBRa8OSdZ?p=preview

One thing is that in your controller you had:
$scope.$watch('$scope.elements',function(newValue){
console.log(newValue);
},true);
It should be 'elements' rather than '$scope.elements'. I'm not quite sure if a $watch or $watchCollection is going to be your best bet here. I tried it but was having issues.
Here is another idea:
var app = angular.module('myApp',[]);
app.controller('FooCtrl', function($scope){
$scope.message = "hi";
$scope.elements = angular.element("input[name='yes']");
angular.element("input[name='yes']").bind("input change", function(e) {
console.log(e);
});
});

Related

Why I cannot access form angular's properites in JS such as $error?

I cannot access angular's Form members. I don't have a clue why. I'm using angular 1.4. The full code is at: http://jsbin.com/lujojiduru/edit?html,js,console,output
angular.module('test',[]).controller('testController', function($scope){
$scope.sendInvitations = function(){
var error = myForm.NewInvitations.$error;
console.log('sent');
console.log('value: ' + error );
};
});
the value of $error is always undefined. Any idea?
var error = myForm.NewInvitations.$error;
should be:
var error = $scope.myForm.NewInvitations.$error;
Notice the $scope
This is assuming you have the name="myForm" on your <form> tag
So something like:
<div ng-controller="testController">
<form name="myForm" novalidate>
...
</form>
</div>
you can also, if you prefer, send in the validity of your form, to your method on the controller.
So:
<button class="btn btn-success" ng-click="sendInvitations(myForm.$valid)">Send Invitations</button>
And in your controller:
$scope.sendInvitations = function(isValid){
if(!isValid)
return;
};
Update
You also don't have any errors.
Add required to your input.
So your controller is now:
angular.module('test',[]).controller('testController', function($scope){
$scope.sendInvitations = function(){
debugger;//
var error = $scope.myForm.NewInvitations.$error;
console.log('sent');
console.log(error );
};
});
and your input
<input style="width: 95%" name="NewInvitations" type="email" ng-model="newInvitations" required />
This is an update to your bin
http://jsbin.com/hebikucanu/1/edit?html,js,console,output
myForm is not accessible in the global scope. You can pass it in as an argument to sendInvitations.
ng-click="sendInvitations(myForm)
$scope.sendInvitations = function(myForm){
It's unlikely that you'd need to do this, though. You can do use the myForm properties in the view.
In angular, you should never touch the DOM. Meaning, you should never invoke HTML elements directly as you would in traditional HTML/JS settings. (read more)
Angular encourages the use of ng-model to employ two-way binding as a means to communicate between the controller and the view. (angular two-way data binding tutorial)
Thus, the first change you should attempt is to replace
var error = myForm.NewInvitations.$error;
with:
var error = $scope.NewInvitations;
This will cause the code to run.
But it appears that you want to retrieve the email input validation error and display it through angular.
Here is an excellent explanation with a tutorial that I think achieves what you're trying to do. If you just want to see the code in action, try this link. (Be sure to hit the Run button.)
Hope this helps!

decoupling $scope.form from controller

In my angular controller, I have to reset some form fields to pristine at a certain point (when some other field changes). The code looks something like this ...
$scope.fieldCallback = function() {
$scope.data.Field = undefined;
$scope.form.field.$setPristine();
}
this of course causes problem once I run my unit tests, because form.field will only be there if you actually parse the document (which of course in the case of unit tests is not happening). I know it is possible to do something along the lines of
var element = angular.element(...[some html]...);
$compile(element)($scope);
but this does not really seem like a good solution to me.
Is there any way to decouple the controller from the html so I don't have to mock this like described above?
Thx in advance!
If I am correctly getting your question, you could try implementing this while focus out of form
<form name="testForm" ... ... ng-blur="func()">
<input type="text" name="Field" />
</form
and in js file
$scope.func = function(){
$scope.testForm.Field.$setPristine();
}
you can drirectly use expresion in ngBlur
ng-blur="focus=false"

Angular UI Bootstrap and Angular Color Picker return undefined for ng-model

In my application i need a color picker with alpha transparency and after searching finally find angular-bootstrap-colorpicker so i try to use this.when normally i use this plugin it work and ng-model correctly but when i use this directive in angular-ui bootstrap , the plugin doesn't work and return undefined.
for this problem i create a jsbin with tabed mode and normal bod .
i have same problem with other directives of angular-ui bootstrap like modal
I know this was asked a while ago.. but for the benefit of anyone else seeing this page.
When an angular binding (such as ng-model) is retrieving a value it will travel up the scope hierarchy until it finds it.. however when setting a value it wont travel up the hierarchy. This is because it is based on how javascript prototype inheritance works.
If you follow this logic then if you bound to a property of an object the binding would then need to travel up the hierarchy to fetch that object and then set a value on it.. therefore as per the updated jsbin note that on the parent controller i am initialising an object on the scope. $scope.colors = {}; and then binding to properties on that object.
<input colorpicker="rgba" type="text" ng-model="colors.back1Color" />
<input colorpicker="rgba" type="text" ng-model="colors.backColor" />
As a rule, Miško Hevery said if your ng-model doesn't have a dot '.' you are probably doing it wrong.
Drammys answer may also work (because he is essentially binding to the 'vm' object, but this is a different style for controllers, along with 'Controller As' syntax and is optional)
I got it working by defining the controller as vm and populating the vm object in the controller...
<body ng-controller="mainCtrl as vm">Normal
<input colorpicker="rgba" type="text" ng-model="vm.back1Color" /><hr/>
<tabset><tab heading="In Tab">
<input colorpicker="rgba" type="text" ng-model="vm.backColor" />
</tab></tabset>
var app = angular.module('app',['colorpicker.module','ui.bootstrap']);
app.controller('mainCtrl',function($scope){
var vm = this;
vm.backColor = '';
vm.back1Color = '';
$scope.change = function(){
alert(vm.backColor);
};
$scope.change1 = function(){
alert(vm.back1Color);
};
});
Personally I prefer to define all the controller properties I wish to expose to the view on this "vm" object in the controller and then declare the controller as vm in the view and bind to the vm object's properties. It feels neater and better defined to me.
Updated the jsbin here.

How do I load an external HTML file and have the scope variables renderred properly in angularJS?

What I am trying to do is after clicking on a buddy in the buddy list, load a chat dialog template HTML file without disturbing other elements in current DOM just like chatting in facebook.
My problem is that after loading the html template file the scope variables such as {{contact.jid}} are not properly rendered, and the controller for the dialog is not even called.
How can I force a rerender or a call on the controller so that those variables are properly renderred? Or should I not use the jQuery.load function to do this? I can't figure out any other way.
Thank you.
Code of the controllers:
// Controller for the chat dialog
ctrl.controller('ChatCtrl',function($scope){
$scope.test = "Test"
});
// Controller for the buddy list
// $scope.toggleDialog is called when a buddy is clicked
ctrl.controller('ContactCtrl',function($scope){
$scope.contacts = window.contactList;
$scope.toggleDialog = function(to){
$.("#chatarea").load("chatdialog.html")
};
});
The controller function of chat dialog is not called after loading chatdialog.html which has an attribute of ng-controller, so the {{test}} variable is not set.
You need to wrap your content that will be compiled inside a directive.
This directive receives the variables and the HTML that will be compiled.
You can wrap this directive in the element that you like:
http://plnkr.co/edit/RYVCrlDmgVXT3LszQ9vn?p=preview
For example, given the following html and variables:
// In the controller
$scope.controllerHtml = '<span>{{variables.myVariable}}</span>';
$scope.controllerVariables = {myVariable: 'hello world'};
<!--In the HTML-->
<div compile-me html-to-bind="controllerHtml" variables="controllerVariables"></div>
You will get the following:
<div>
<span>hello world</span>
</div>
You are loading the external HTML via jQuery and Angular has no way of knowing how to use it. There are two ways to solve this issue:
use ngInclude to load the template from the server, angular will load it from the server and compile it for you to use.
continue to use jQuery load the HTML from the server and use the $compile service to teach angular how to use it
I would highly suggest using method #1 to load your external template.
I suppose the:
$.("#chatarea").load("chatdialog.html")
is the jQuery .load, or something similar. I would get the template via ngInclude, checking if test is setted or not; html:
<div id="chatarea" ng-if="test">
<div ng-include="'chatdialog.html'"/>
</div>
controller:
ctrl.controller('ContactCtrl',function($scope){
$scope.contacts = window.contactList;
$scope.test = '';
var callbackFunction = function(data) {
$scope.test = data.test;
};
$scope.toggleDialog = function(to){
AjaxRequestToGetBuddyInfoAndMessages(to, callbackFunction);
};
});
Obviously test will be a more complex object, so the ngIf test will be different (and you will need to take into account the fact that:
$scope.test = data.test
if they are objects, they will lose the reference and have an unwanted behaviour).

Rendering dynamic HTML(angularjs content) content after ajax call in AngularJS

I am new to Angular getting stuck after making ajax call. How do I render/compile the html content once you inject in DOM so that I can still use the AngularJs functions.
Due to the way my backend is set up I have to get content via ajax ($http). And I am making the app without jQuery. I tried $compile and $apply but didn't work. What am I missing here.
I have the code set up at http://jsfiddle.net/rexonms/RB7FQ/3/ . I want the second div content to have the same properties as the first div.
HTML
<div ng-controller="MyCtrl" class="section">
<input ng-model="contentA">
<div>
And the input is: {{contentA}}
</div>
</div>
<div ng-controller="MyAjax" class="section">
<div id="dumpAjax">
{{ajaxData}}
</div>
<button ng-click=getajax()> Get Ajax</button>
</div>
SCRIPT
var myApp = angular.module('myApp',[]);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
}
function MyAjax($scope){
var data = '<input ng-model="contentB">{{contentB}}';
$scope.getajax = function(){
$scope.ajaxData = data;
}
}
Thanks in advance.
ng-bind-html-unsafe is not available 1.2 and later verison of angular...
so you should use ng-bind-html which creates a binding that will innerHTML the result of evaluating the expression into the current element in a secure way.
using $scope variable in your string make it unsafe, so you should use $sce.trustAsHtml but this time variables in your string cannot be bind because they will be not compiled...
basically you should compile your string in order to bind your variables. Here comes custom directives you can create a directive which can replace with ng-html-bind...
Writing a custom directive which extends ng-bind-html with some extra functions can be a solution...
here is my PLUNKER
and here is your updated JSFIDDLE with my solution...
Instead of {{ajaxData}}, you should use something like:
<div ng-bind-html-unsafe="ajaxData"></div>
However, you'd still need to set the proper model to bind the contentB and get it working.

Resources