AngularJS - Access Model Property Without Controller - angularjs

I have been following some of the introductory AngularJS tutorials and they start off by showing how easy it is to get started.
They say all you have to do is define ng-app and then use the example of an input with ng-model="name" and then show that string as you type using {{name}}.
My question is, is it possible to access and read the 'name' property without having to define a controller and read it using $scope.name?
For example..
$(function () {
var name = ?.name;
});

Well as it turns out, setting ng-model without a ng-controller defined at any parent level creates the item on the $rootScope.
What it also means that whereever $rootScope dependency can be injected you can get access to variable you define in the view.
See my fiddle here
Update: Based on the question update. You can access the scope outside from angular using something like
angular.element(domElement).scope()
and the access the variable. See this answer. But please avoid as much as possible.

Related

Angularjs dynamically added ng-model is not accessible by $scope, shows undefined

I am creating form, where few fields are dynamic, ng-model is added dynamically.
Ex.:
form.append("<input type='hidden' name='paymillToken' value='" + token + "' data-ng-model = 'formdata.token'/>");
This fields shows undefined while I try to access using $scope.formdata.token
Following is another scenario where I am adding fields via ajax.
angular.forEach(data.data, function(obj, key) {
list+='<div class="items text-center"><img src="assets/uploads/discs/'+obj.image+'" class="img-circle"><br><input type="radio" id="chkDisc'+obj.id+'" name="disc_id" value="'+obj.id+'" required data-ng-model="formdata.disc_id" /></div>';
});
$scope.discslist = $sce.trustAsHtml(list);
This model disk_id is not accessible too.
Okay, to expand on my comment and a bit more on what everyone else here is saying to you, the main issue you're having is inherent in your approach. The way you're trying to manipulate the DOM is very un-AngularJS.
In AngularJS, when you want to change what is displayed to the user (the view), you make changes to your model (your controller scope). That means, you have to set up your view to be able to respond to those changes. We do that with directives and expressions in Angular.
You're probably already using directives to respond to changes in your model whether you realize it or not. ngRepeat, ngModel, ngShow, ngIf, ngInclude, are a handful you're probably familiar with, and even forms and form elements like inputs are actually directives in Angular. When you use these, a change in your model (such as loading data into the controller scope) signals to Angular that it should check whether that change affects any of the directives in your view, and if so, respond to it by updating the view.
In order to do this, Angular needs to know which parts of the model are connected to which parts of the view. It makes these connections when it compiles the html elements that are added to the page. This compile process happens automatically when you load an Angular app. After that, it's up to us to tell Angular when to compile html that is added to the page.
More often than not, we do this without even realizing it. For example, when you use the ngView directive, it will compile the template for each route that it loads, so that all of the directives in your template are properly linked with their associated model.
I know this is a long explanation, but there are two very important points here that are essential to learning AngularJS:
To change the view, you change your model and let the directives (and expressions) on your page respond to those changes.
When you add html elements to the page, if you want AngularJS to be able to use them in your view, they must be compiled first. The compile process should be done via a directive (either a built in one or a custom one).
So, how does all of this apply to your question?
First, I'm guessing that you're breaking both rules by trying to manipulate the DOM via a controller. Even if it is possible to use $compile in a controller, using a controller to change the DOM is bad practice and simply wrong to do (read the part in that link to the doc that specifically states: Do not use controllers to: Manipulate DOM...). A good rule to remember when you're learning AngularJS is that the only time you should ever be using JQuery or JQLite inside Angular is when you are creating a custom directive.
Okay, so how do you solve your question? Use a directive. It looks like you've got a case where you're trying to iterate over an object called data and add some inputs that correspond to the data.data property. This sounds like a job for ngRepeat.
The first thing you need to do is add your data to your controller and make sure it is accessible to the view. The easiest way to do this is by injecting $scope into your controller and setting the data on a scope variable. In its simplest form, that might look something like this:
angular.module('MyApp', [])
.controller('MyController', ['$scope', function($scope){
$http.get('/some/url/that/returns/the/data').
success(function(data) {
$scope.data = data;
});
}]);
Now that we have the data somewhere that we can access from the view, we can use it with the ngRepeat directive in our html, something like this:
<div ng-controller="MyController">
<div class="items text-center" ng-repeat="disc in data.data">
<img ng-src="assets/uploads/discs/{{disc.image}}" class="img-circle"><br>
<input type="radio" id="{{'chkDisc' + disc.id}}" name="{{disc.disc_id}}" value="{{disc.disc.id}}" required data-ng-model="formdata[disc.disc_id]" />
</div>
</div>
This is a common issue. By updating the value and not the model angular has no idea that the value in the field has been updated. As the first commenter said updating in this manner is completely unnecessary when using ng-model.

In AngularJS, from a controller, how do I add a value to a invalid input?

I'm new to Angular, and working on my first full webapp with it.
I have a form with a field that is required. So, I understand that it's bound ngModel value will be undefined. The user can choose to enter the value in the field manually, or they can click a button triggering a function that will populate it.
By default the field is blank and invalid and I'm unable to set it's value from the controller.
In the view:
<input type="number"
min="0"
max="50"
placeholder="0"
name="entry-total-score"
id="entry-total-score"
ng-model="entry.total.score"
required />
In the controller:
$scope.entry.total.score = computedTotal;
How can I initialize that data binding manually?
My guess is that you are simply forgetting to initialize total before trying to set score in your controller. It is also possible that (like Ben Diamant pointed out) that you are not setting your variable in your scope correctly.
The correct way to set it in the scope would be: $scope.entry.total.score = computedTotal;
You should be adding variables to the $scope or to "this" in the controller in order to access those variables in your angular HTML.
If you go the second route you need to make sure that you use the ng-controller="<ControllerName> as <RefName>" then use it in your HTML based on your ref name.
I made an example that I believe does what you want.
http://plnkr.co/edit/fbz1nSHPGZN2k4oYCCFA?p=preview
I hope this helps
you can also use jquery with angular, in your controller.
jQuery('#entry-total-score').val(computedTotal);
if you actually want the work and computedTotal is not a variable use .val("computedTotal")
If you want to only use angular then i think Ben's comments should work. It is nice to know though that angular and jquery play super nice. Instead of using the '$' for jquery just use jQuery and eveything works great. Also make sure to include jquery in your header with a

Angularjs directive: Passing a model reference to an isolated scope

I 'm trying to write a collapsible, reusable calculator directive, that binds to an input field (in the parent scope). This input field itself has a ngModel binding.
When the user presses the equals-button of my directive this parent scope model should be updated. I need to isolate the scope so I can reuse it:
Here is the simplified code and how I would like to use it:
http://plnkr.co/edit/OSOcxydJWh8K520nstAU?p=preview
I tried passing in the values as an attribute. but that does not work because I don't know how to update this attribute inside of the controller(I tried the $attrs service).
So how can I update the model from the directive?
Maybe you're overthinking it, maybe I'm underthinking it. Either way, here's all I did to change yours to make it work:
if ($scope.operator ==='+') {
$scope.field = parseInt($scope.field) + $scope.operand;
}
I uncommented your scope and then I made sure that your controller made reference to the data you had exposed in your scope. That's it.
And here's a working version of your Plunker: http://plnkr.co/edit/btBi3E
You need to use ngModelController. Here's a link with docs, with a handy example:
NgModelController

AngularJS - access model from another directive

Here's a plnkr.
How do I access the headerInput model from within the sideMenuContent directive? Let's say I have 10 other ng-models in sideMenuHeader directive that I want to access in sideMenuContent, is there any way of making it easily scalable?
You need to use the dot notation for objects. See Understanding Scopes in AngularJs
So instead of headerInput, use something like menu.headerInput and also make sure to initialize a menu object in your controller like so $scope.menu = {}; (or you can also set default values).
I updated your plunkr to show you how it works

AngularJS - ng-bind-html-unsafe and ng-model Problems

I have the following line in my html:
<div ng-bind-html-unsafe="departmentConfig" class="control-group"></div>
and I use a $resource get to retrieve the HTML, assign the HTML to $scope.departmentConfig, and then the view is updated perfectly. The HTML that is assigned to $scope.departmentConfig contains form elements, with ng-model attributes in it, but when I change the values in these input elements, they don't update the $scope model at all.
This is what I have tried, based on a lot of other internet posts, and it isn't working:
$resource('resources/sources/departments/:mappedName', {
mappedName:departmentKey
}).get(function(departmentConfig) {
// This will call another function that will build a chunk of HTML
$scope.departmentConfig = $scope.buildDepartmentConfigHtml(departmentConfig);
// This is my feeble attempt to access the element, and bootstrap it to include the items in the $scope model.
var $departmentConfigContainer = $('#departmentConfig');
angular.bootstrap($departmentConfigContainer, ['sourcemanager']);
I have even seen some jsFiddle examples where this appears to be working, but mine isn't. Am I calling bootstrap too soon? I also tried putting a $watch on $scope.departmentConfig like this:
$scope.$watch('departmentConfig', function() {
var $departmentConfigContainer = $('#departmentConfig');
angular.bootstrap($departmentConfigContainer);
});
but it didn't work either. I bet there is an easy explanation to this, I just can't seem to get the input elements with ng-model that are loaded after page compile to get bound to the model. Any help is appreciated, this is the last piece of functionality I need to get working on my page. Let me know if you need more information about my configuration as well.
So, simply put, how can I force a section of the DOM to recompile after I know it has been loaded?
UPDATE
Here is a jsfiddle outlining what I would like to do: http://jsfiddle.net/j_snyder/ctyfg/. You will notice that property two and three don't update the model, and I am calling bootstrap on the outer div, hoping that will include those in the model binding. This is the first time I have posted to jsfiddle, please let me know if you can't see the example.
ng-bind-html is made for regular HTML, not compiling new angular elements.
You will have use the $compile service.
Here is how you would edit your current example to work: http://jsfiddle.net/andytjoslin/ctyfg/21/. But this way ends up being bad, because you have to do DOM manipulation in your controller.
You just need to create a directive that will basically do what you wanted ng-bind-html to do: http://jsfiddle.net/andytjoslin/ctyfg/22/

Resources