Apply jquery after rendering angularJS HTML - angularjs

i have rendering HTML after AngularJS call
Its controller is
App.controller('controller', ['$scope', '$http', '$sce', '$routeParams', '$location', function ($scope, $http, $sce, $routeParams, $location) {
$http({
//http call
}).then(function (response) {
$scope.requestpurpose = $sce.trustAsHtml(response.data.requestpurpose);
$scope.$watch('requestpurpose', function(newValue, oldValue) {
if(typeof newValue != 'undefined'){
alert(newValue);
showAlreadySelected();
}
});
}]);
and its jquery script is
<script type="text/javascript">
// it will show the div depending on purpose of request
function showAlreadySelected(){
if ($("#1").is(":checked")) {
$("#veterinarian-info").show();
} else {
$("#veterinarian-info").hide();
}
}
</script>
This is my HTML
<div class="row purpose-box" >
<div class="col-sm-12" ng-bind-html="requestpurpose"></div>
</div>
and after ajax call below html is renering in ng-bind-html
<div class="boxes-check">
<div class="box-one">
<input checked="checked" rev="Annual exam" type = "checkbox" name = "request_purpose[]" ng-model=formData.request_purpose[1] onChange="angular.element(this).scope().changePurpose(this)" value = "1" class = "md-check" id = "1" >
</div>
<div class="box-two">
<label title="" for="1">
<span></span>
<span class="check"></span>
<span class="box"></span> Annual exam
</label>
</div>
</div>
<div class="boxes-check">
<div class="box-one">
<input checked="checked" rev="Spay or neuter surgery" type = "checkbox" name = "request_purpose[]" ng-model=formData.request_purpose[2] onChange="angular.element(this).scope().changePurpose(this)" value = "2" class = "md-check" id = "2" >
</div>
<div class="box-two">
<label title="" for="2">
<span></span>
<span class="check"></span>
<span class="box"></span> Spay or neuter surgery
</label>
</div>
</div>
but i am facing problem is after angular load its calling showAlreadySelected function but does not selected "#1" and one thing if any body can help is any Jquery function which will hit whenever input element with id "#1", "#2" render into my ng-bind-html div.

First, I would move the watcher outside the then because you're registering a new watcher everytime you make the ajax call.
I tried, it works to have a number as ID (but not recommended though). We'll need your HTML code as well cause it should work the way you've implemented. Is the #1 node added by the ajax call ( = present in $scope.requestpurpose) or is it always present in the DOM ?
Also, can you add a console.log in the showAlreadySelected function to be sure it's called.
EDIT
App.controller('controller', ['$scope', '$http', '$sce', '$routeParams', '$location', function ($scope, $http, $sce, $routeParams, $location) {
$http({
//http call
}).then(function (response) {
$scope.requestpurpose = $sce.trustAsHtml(response.data.requestpurpose);
showAlreadySelected();
});
}]);

I have bind class with DOMSubtreeModified to detect changes within a div
$('.purpose-box').bind("DOMSubtreeModified",function(){
showAlreadySelected();
});

Related

Cannot read property 'nid' of undefined, need to pass object to another controller

I'm having issues trying to pass a selected value from one controller to another controller.
View (I pass the NgValue to $scope in Controller).
<li class="list-group-item" ng-repeat="item in filterData = (informes | filter:{title:searchTitle, resolucion:searchReso, year: searchYear}) | limitTo:10:10*(currentPage-1)">
<div class="wrapper">
<div class="informes" ng-value="nodeID(item)">
<a ng-href="../node-informes/node-informes.html">
<p class="text-center text-truncate">
<small>{{item.title}}</small>
</p>
</a>
</div>
</div>
</li>
Controller. I have the "Item in that Controller" and the console prints it.
informes.controller('InformesCtrl', ['drupal', '$rootScope', '$scope', '$http', 'InformesFtry', function(drupal, $rootScope, $scope, $http, InformesFtry) {
$rootScope.getData = function(informes){
$rootScope.nodeID = function(item){
$rootScope.node = item.nid;
console.log($rootScope.node);
};
}
}]);
2nd Controller in another module (gives me "Cannot read property 'nid' of undefined" error").
nodeInformes.controller('NodeInformesCtrl', ['$rootScope', '$scope', '$http', '$controller', function($rootScope, $scope, $http, $controller) {
$controller('InformesCtrl', {$scope: $scope});
$rootScope.getData(informes);
$rootScope.nodeID(item);
$scope.node = $rootScope.node;
console.log($scope.node);
}]);
It supposed that i called the other controller with parameters (saved value in "$rootScope.node", passed it to 2nd controller, but it gives me the error that's undefined).
consolelog in first controller works, but not in second controller.
I appreciate any suggestion.
Modified as code suggested, but seems that the "item" object is not passing the right way.
Try to avoid using $rootScope unless you absolutely have to (raising or handling events is about the only time I've ever used $rootScope) - instead you can use a service to reliably pass data between controllers. In AngularJS services are singletons so all of your controllers have access to the same instance. You can take advantage of this and use the service to "pass" (more accurately share) data between controllers.
Here is a simple example to demonstrate the concept which you can then apply to your situation. Normally you wouldn't have two controllers in a single view like this, but for illustration purposes (and being able to run in the SO snippet engine) I've done it here. Just to prove that I'm not sharing any controller variables I've named them differently.
angular.module('app', [])
.service('sharedService', function() {
var service = {};
service.sharedObject = {};
service.sharedObject.value = "Set in service";
return service;
})
.controller('ctrlOne', function($scope, sharedService) {
$scope.sharedObjectC1 = sharedService.sharedObject;
})
.controller('ctrlTwo', function($scope, sharedService) {
$scope.sharedObjectC2 = sharedService.sharedObject;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="ctrlOne" style="margin-bottom: 30px;">
<h1>Controller One</h1>
Modifying this value will update it in Controller Two:
<div>
<input ng-model="sharedObjectC1.value" />
</div>
</div>
<hr>
<div ng-controller="ctrlTwo">
<h1>Controller Two</h1>
Modifying this value will update it in Controller One:
<div>
<input ng-model="sharedObjectC2.value" />
</div>
</div>
</div>

Invoke parent controller while loading child controller

I have the parent view defined as:
<div ng-app="myProSupMod" ng-controller="DefaultController" class="container">
<div class="row">
<div class="col-md-12">
<div class="page-header">
<img src="~/Content/Images/logo.jpg" />
<b class="projectTitle">Production Support Tool</b>
</div>
</div>
<div ng-show="DefaultProps.UserDivVisible" class="page-header"
style="font-weight:bold;height:30px;border-bottom:1px solid #d1d1d4;width:100%">
<div style="float:right;"><span style="margin-right:10px;">
Welcome
<a class="text-success" href="#">
{{DefaultProps.LoggedInUsername }}
</a></span>|
<a href="#" style="margin-left:5px;" class="text-danger"
ng-click="LogUserOut()">Logout
</a>
</div>
</div>
</div>
<ng-view></ng-view>
</div>
Its controller:
myProSupMod.controller("DefaultController", ['$scope', '$rootScope',
'$location', '$route', function ($scope, $rootScope, $location, $route) {
if (!sessionStorage.getItem("LoggedInUsername")) {
$scope.DefaultProps = {
LoggedInUsername: "",
UserDivVisible: false
};
$location.path('/');
}
else {
$scope.DefaultProps = {
LoggedInUsername: sessionStorage.getItem("LoggedInUsername"),
UserDivVisible: true
};
}
$scope.LogUserOut = function () {
sessionStorage.setItem("UserDivVisible", false)
$location.path('/')
}
}])
And one of my child child controller is like
myProSupMod.controller("LoginController", ['$scope', '$rootScope',
'$uibModal', 'LoginService', '$location', function ($scope, $rootScope,
$uibModal, LoginService, $location) {
$scope.DefaultProps.LoggedInUsername = ""
$scope.DefaultProps.UserDivVisible = false
$scope.Login = {
Username: '',
Password: '',
Error: '',
validateLogin: function () {
$scope.Login.Error = ''
$scope.DefaultProps.LoggedInUsername =
sessionStorage.getItem("LoggedInUsername")
$scope.DefaultProps.UserDivVisible =
sessionStorage.getItem("UserDivVisible")
$scope.Login.Username = $scope.Login.Password = ''
$location.path('/Home')
}
}
}])
The statements
$scope.DefaultProps.LoggedInUsername=sessionStorage.getItem("LoggedInUsername")
and
$scope.DefaultProps.UserDivVisible =sessionStorage.getItem("UserDivVisible")
are really changing the values of the properties in the "Default" controller but routing to an other view both the "Default" controller properties "LoggedInUsername" and "UserDivVisible" are gone.It looks like i may need to have both the above statements in every other view i'm going to navigate to.
Is there an other way?
"Default" view being the parent, the controller is invoked only once at the start of the application upon navigating to other view the "Default" controller is never invoked.
But if i reload any page by clicking "reload" on the browser or hitting "enter" on the URL i see the "Default" controller being invoked, which is what i want to happen when i'm also navigating to other view via angular routing.
For clarity, here is a simplified template:
<div ng-app="myProSupMod" ng-controller="DefaultController">
<div ng-show="DefaultProps.LoggedInUsername">
Welcome {{DefaultProps.LoggedInUsername}}
<button ng-click="LogUserOut()">Logout<button>
</div>
<ng-view></ng-view>
</div>
Make the controller lightweight:
app.controller("DefaultController", function($scope, LoginService) {
$scope.DefaultProps = LoginService.getProps();
$scope.LogUserOut = function () {
LoginService.logout();
};
})
With the functions inside a service, they can be called by any controller and they are encapsulated in a way that makes the code easier to understand, debug, and maintain.

Angularjs scope not working

I am using basic angular.js concept to show and hide a div. For some reasons I am unable to make it work.
While Uploading a file I am showing a div 'myFormSpinner' on the basis of registerStart value. I am creating a phone gap app.
Could someone please help me in finding the issue. Apart from showing/hiding div everything works fine. Below is the code snippet:
<div class="row" ng-controller="RegisterCtrl">
<div id="myFormSpinner" ng-show="registerStart">
<img src="img/ajax-loader.gif">
</div>
<div class="col-md-8">
<form class="ng-pristine ng-invalid ng-invalid-required" style="margin-top:5%;">
<div class="col-md-6">
<input class="form-control " type="text" ng-model="registerData.Email" id="Email" name="Email" required placeholder="Email">
</div>
<div class="col-md-offset-1 col-md-10 ">
<input type="submit" ng-click="register()" value="Register" class="btn btn-default btn-primary">
</div>
</form>
</div>
event.controller('RegisterCtrl', ['$scope', '$state', '$q', '$http', 'eventService', 'authService', '$stateParams', '$rootScope', 'tokenService', 'imageService', 'spinnerService', 'appBackgroundService',
function ($scope, $state, $q, $http, eventService, authService, $stateParams, $rootScope, tokenService, imageService, spinnerService, appBackgroundService) {
var userNumber = 0;
$scope.mediaUploadStart = false;
$scope.eventId = $state.params.id;
$scope.register = function () {
$scope.registerStart = true;
console.log('scope.Pic=' + $scope.pic);
if ($scope.registerData.Email) {
spinnerService.show('myFormSpinner');
$scope.mediaUploadStart = true;
var paramOptions = {
eventId: $state.params.id,
email: $scope.registerData.Email,
fb: {},
number: userNumber,
provider: "Form"
};
uploadPicAndData(paramOptions).then(function (result) {
var data = JSON.parse(result);
$scope.registerStart = false;
appBackgroundService.disableBackgroundMode();
},
function (error) {
spinnerService.hide('myFormSpinner');
$scope.registerStart = false;
appBackgroundService.disableBackgroundMode();
});
$scope.mediaUploadStart = false;
spinnerService.hide('myFormSpinner');
}
};
}])
You are setting the $scope element in an async mode.
the digest cycle is not able to determine that a change has been made to the scope element in an async mode.
You should use $apply to activate the digest cycle.
$scope.$apply(function () { $scope.registerStart = false; });
Read more about $apply here: http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

Controller triggered via factory

I am still a novice with angular. I have asked a question similar to this before, but it seems to be a different issue at work here.
I have two controllers and a factory sharing information between them. I have two separate divs using two different controllers to show / hide using ng=show;
HTML
<div id=main>
<div ng-controller="Ctrl1">
<div ng-show="var1">Hidden Stuff</div>
</div>
<div ng-controller="Ctrl2">
<div ng-show="var1">More Hidden Stuff</div>
</div>
</div>
Both use the same var for ng-show, shared by a factory
JS Factory
app.factory('Srvc', function($rootScope) {
var Srvc = {};
Srvc.var1;
return Srvc;
});
JS Controllers
app.controller('Ctrl1', function($scope, Srvc) {
$scope.var1 = false;
if (user interacts with html in div with ng-controller="Ctrl1") {
$scope.var1 = true;
Srve.var1 = $scope.var1;
}
});
app.controller('Ctrl2', function($scope, Srvc) {
$scope.var1 = Srvc.var1;
if ($scope.var1 === true) {
update HTML in div with ng-controller="Ctrl2"
although I shouldn't need to do this really should I?
}
});
So from what I can tell the factory works ok, the data is saved in the factory Srvc.var1. However when I pass the data true to Srvc.var1 I cannot seem to get Ctrl2 to 'trigger' and update its html with ng-show=true
One way to solve this problem without explicitly creating a watcher, is to wrap var1 in an object inside the service and then pass this object as a $scope variable for both Ctrl1 and Ctrl2 controllers.
DEMO
Javascript
.factory('Svc', function() {
var service = {
data: {}
};
// If you perform http requests or async procedures then set data.var1 here
service.data.var1 = true;
return service;
})
.controller('Ctrl1', function($scope, Svc) {
$scope.data = Svc.data;
})
.controller('Ctrl2', function($scope, Svc) {
$scope.data = Svc.data;
});
HTML
<div id="main">
<div ng-controller="Ctrl1">
<div ng-show="data.var1">Hidden Stuff</div>
<button type="button" ng-click="data.var1 = true">Set data.var1 to true</button>
<button type="button" ng-click="data.var1 = false">Set data.var1 to false</button>
</div>
<hr>
<div ng-controller="Ctrl2">
<div ng-show="data.var1">More Hidden Stuff</div>
<button type="button" ng-click="data.var1 = true">Set data.var1 to true</button>
<button type="button" ng-click="data.var1 = false">Set data.var1 to false</button>
</div>
</div>
So it seems I need to $watch the service for a change within the controller.
Original answer is here.
app.controller('Ctrl2', function($scope, Srvc) {
$scope.$watch(function () {
return Srvc.var1;
},
function(newVal, oldVal) {
$scope.var1 = newVal;
}, true);
});
I think setting Var1 to $rootScope instead of Srvc should work, just call $scope.$root.$digest() after updating var1.
and use ng-show=$root.Var1 in view.

how to call http request on ng-click event?

I am using angularjs on front end. I have two input boxes on index.html (namely first-name and last-name), and one button. On the click of button (ng-click="search()") I want to call an http GET request with first-name and last-name as parameters. And then I want to show the response in the same page in some other DIV tag. How would I achieve this?
HTML:
<div ng-app="MyApp" ng-controller="MyCtrl">
<!-- call $scope.search() when submit is clicked. -->
<form ng-submit="search()">
<!-- will automatically update $scope.user.first_name and .last_name -->
<input type="text" ng-model="user.first_name">
<input type="text" ng-model="user.last_name">
<input type="submit" value="Search">
</form>
<div>
Results:
<ul>
<!-- assuming our search returns an array of users matching the search -->
<li ng-repeat="user in results">
{{user.first_name}} {{user.last_name}}
</li>
</ul>
</div>
</div>
Javascript:
angular.module('MyApp', [])
.controller('MyCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.user = {};
$scope.results = [];
$scope.search = function () {
/* the $http service allows you to make arbitrary ajax requests.
* in this case you might also consider using angular-resource and setting up a
* User $resource. */
$http.get('/your/url/search', { params: user },
function (response) { $scope.results = response; },
function (failure) { console.log("failed :(", failure); });
}
}]);

Resources