Call method on Angular scope from Underscore Template - javascript

I have an underscore template that is called from an Angular controller. I have a dropdown on the template and a call to onchange on the dropdown. The onchange attempts to calls a method on the scope on the controller. I have tried everything to get the method called in the onchange but doing this
<select onchange="foo(this.value)">
gives me
foo is not defined
and
<select onchange="scope.foo(this.value)">
gives me
scope is not defined
and
<select onchange="$scope.foo(this.value)">
gives me
$scope is not defined
Is it even possible to call a method on the controller in this way?

In the code that is calling the _.template() function, assuming its putting the templated value into a variable and has access to scope:
Find the element in the templated markup: var select = $(templatedVar).find('#selectId');
Add a change event: select.change(function() { //call scope function });

use ngChange instead attribute of onchange
check this link for more info "https://docs.angularjs.org/api/ng/directive/ngChange"

Related

Multiple parent-child scope event trigger issue

I have a directive for parent scope, I also have another directive for child scope. In a template, I have several parent-child scope. Like this.
ParentScope1
- ChildScope1
ParentScope2
- ChildScope2
If I change a value in Parent, I will broadcast it to Child. I am using $rootScope.$broadcast to broadcast from parent. I am using $rootScope.$on to accept this change in child.
My problem is:
Now, If I change a value in ParentScope1, it will broadcast to ChildScope1. Then I will change a value in ParentScope2, it will broadcast to ChildScope2, but it will also broadcast to ChildScope1.
I want: Change a value in ParentScope1, it will broadcast to ChildScope1. Change a value in ParentScope2, it will broadcast to ChildScope2. I search online for some time but did not find the solution for it. Maybe I did not use the correct keywords for searching it. Please advise. Thank you.
In your definition of directive set
scope : true
then use
$scope.$broadcast
$scope.$on
this should probably works fine
post your code so we have a better view of the problem
You are looking for communication between parent and child directive, you can use below approach but both directive will be tightly coupled using this-
Require a controller - Get the handle of same node of parent node directive controller.
Require: '^parnetDireName' is used to find the controller on parent node. Without ^, it will find for same node only. '?' is used when controller may not be available.''?^", "?^^", "^^". Fourth parameter of link function is used to get the controller. It can use the controller prop/method. You can also access multiple controller because Require will have array - require: ['^dir1','^dir2']. Link function will have cntrl array and it can be access through array element in the same sequence
Pre link and post link function for nested directive -
Default link function is post link function.
Use keyword post to define it explicitly
Child post link function is executed first if parent and child both has Post link function
Parent link function is executed first if both parent and child has pre-link function.
Controller is executed before link function
---------------------------------Another decoupled way ---------------------
There are three ways to setup the relation between directive scope and containing controller scope-
- Directive with shared scope with containing controller. Any new
item/modified item by directive will be part of parent scope. It is
default or scope:false
- Directive with inherited scope. Any new item added by directive will not be visible by containing controller. Directive scope can read all data from parent scope. Use scope:true property to activate it. Child can see parent data and can override or create new variable.
- Isolated scope. Both scope cannot read each other data. Object mapping is required to read the parent data. Directive scope mapping will have object name and same object will be passed from html. There are three ways to receive the parameter-
- Complete object Data -> '=' is used
- Simple value like flag as a String- '#' is used . '#sampleVar', where sampleVar is the name of variable in the html.
Scope {
cntrollerStrVarName: '#htmlStrVarName'
}
- Function parameter - '&' is used to pass the parameter. Method parameter can be overridden using ({paramName: 'value'})

Difference between on-change and ng-change

Below is a pretty straightforward setup for a form drop down list. However, the on-change event refuses to fire... unless it's changed to ng-change.
This had me stuck for about an hour, since we use the same setup elsewhere in our site (i.e. model property/list/on-change directive) without fail.
I'm wondering what the difference is between on-change and ng-change and why one works in this instance and the other doesn't?
View
<select id="grArchive"
name="grArchive"
class="form-control"
options="userList"
ng-model="selectedUser"
ng-options="user as user.name for user in userList"
on-change="showSelected()">
</select>
Controller
scope.selectedUser = {};
scope.userList = [];
scope.showSelected = function(){
scope.columns = addColumns;
};
var loadUserList = function(data){
scope.userList = $.map(data, function(item){
return {id: item.id, name: item.firstName + ' ' + item.lastName};
});
}
Just in case: the user drop down populates as expected (screen shot below)
ng-change
ng-change is a directive provided by Angular core API which internally registers an expression to be called when any change happens in $viewValue of ng-model variable (here is the code); assign it an expression such as myFunction(). That provided expression will evaluate inside the underlying controller scope. After calling an expression it runs a digest cycle to make sure bindings are updated on the view. Besides ng-change there are other directives used for events, like ng-focus,ng-mousedown,ng-submit, ng-blur, etc. Here is a list of such directives
on-change
It is a way of calling a JavaScript function on change of input element value. It will search for the function which is globally available in context (obviously it will not call the function registered in angular controller) and evaluate it.

Difference between defining a variable using ng-model, not by a controller in AngularJS

I can't understand the behavior of a variable in the following two different code snippet.
<body ng-app="">
<input ng-model="name">
{{name}}
</body>
The above code doesn't uses any controller for the variable 'name'
<body ng-app="myApp" ng-controller="NameController">
<input ng-model="name">
{{name}}
<script>
var app = angular.module('myApp', []);
app.controller('NameController', function($scope) {
$scope.name="";
});
</body>
In this code snippet, I have used a controller.
The $scope in an AngularJS is a built-in object, which contains application data and methods. You can create properties to a $scope object inside a controller function and assign a value or function to it.
in the second case you defined variable in scope of function it will not available out side and you have to use inside the controller you dont need to get the variable value from dom if you want to pass the value of name you can use $scope.name
1st one is just assign ngModel in html if you want to use the value you have to get the value from angular.element() function other you can just print it in html
I did some quick research on SO and came to the conclusion that in the first case everything is simply being defined in the global scope of the application and the application has no name so you are basically unable to assign any controllers, directives etc. to your application but it's working.
The second way is the right way to do it: your application (or module) has a name, it is assigned to a variable and therefore you can assign factories, controllers, directives etc. to the application.
Source: ngApp without using any specific module name.

Using ng-change in AngularJS with "Controller As" syntax

I am trying to avoid using $scope in my controller function, instead opting to use
var viewModel = this;
with "controller as" viewModel syntax.
My problem is that I need to use ng-change to call a function in my controller but while I am able to access data from a service, I am unable to call functions.
//Controller
(function () {
'use strict';
angular
.module('app')
.controller('GeneralSettingsController', GeneralSettingsController);
GeneralSettingsController.$inject = ['SimulationService'];
function GeneralSettingsController(SimulationService) {
var viewModel = this;
viewModel.SimulationService = SimulationService;
viewModel.setSimulationPeriod = setSimulationPeriod;
function setSimulationPeriod() {
console.log("Entered local setSimulationPeriod");
viewModel.SimulationService.setSimulationPeriod();
}
}
})();
The controller is being instantiated in a directive that defines the controller and controllerAs: 'viewModel'
My html looks like this:
<div class="col-xs-2">
<input type="text" class="form-control" id="startyear" name="startyear" placeholder="start year"
autocomplete="off" value="2017" maxlength="4"
ng-model="viewModel.SimulationService.data.simulationPeriodStart" ng-change="viewModel.setSimulationPeriod">
</div>
I was able to call things fine when I used $scope instead of referencing the controller however I feel this is not ideal. I was hoping there is a way of calling a function with ng-change that still uses viewModel.
angular expressions
You're not calling the function. Instead try:
<input ng-change="viewModel.setSimulationPeriod()">
Note the () at the end of your function. Ng-change, like most other angular directives use expressions, meaning they're actually trying to execute a subset of JavaScript. In this case when you just passed a reference to your vm's function, it simply evaluated it rather than executing it.
order of assignment
Also, you've defined the viewModel function before you've defined the function you're setting it to. Move the function declaration above the part of your code where you assign it to your viewModel.
instead of this
viewModel.setSimulationPeriod = setSimulationPeriod;
function setSimulationPeriod() {
console.log("Entered local setSimulationPeriod");
viewModel.SimulationService.setSimulationPeriod();
}
reorder it like this
function setSimulationPeriod() {
console.log("Entered local setSimulationPeriod");
viewModel.SimulationService.setSimulationPeriod();
}
viewModel.setSimulationPeriod = setSimulationPeriod;
jusopi was right. My controller was not wired up correctly. The problem was that I had another controller active at a higher scope which was also set to controllerAs: viewModel. This caused me to reference the wrong controller where the function did not exist. Once I gave this controller a unique name everything went smoothly which is why it worked for $scope.

Isolate Scope 2 way bindings doesn't update the value of parent scope

Hello I have directive foo in which controller I have
$scope.valid = false
I am passing this variable inside another directive through isolated scoping in my template
<bar valid="valid">
and using an ng-if inside my template
<span ng-if="valid">Validated<span>
Now when I update valid in my child directive. It shows validated in my template. But the variable did not update in my parent directive controller. Why this is happening?
Note: In my child controller I am attaching the variable to controller instead of scope. Is this the reason it is behaving like this.
Indeed, if, in your child directive controller code, you write
function MyController($scope) {
this.valid = $scope.valid;
}
then setting the controller object's valid property is not going to change the $scope.valid, because you performed a copy of valid.
Instead, keep using $scope to pass the information about the change back up to the parent.

Categories

Resources