ngClick event not fire after html binding - javascript

I binded html data from angular js post to Html div, but not ng click is fired in the binding html content.
This is my binding html div.
<div ng-app="SupportManagement">
<div ng-controller="SupportCtrl">
<div ng-click="openModal(5)"></div>
<div id="detailBlock"></div>
</div>
</div>
This my bind function with Angularjs Post
angular.module("SupportManagement", [])
.controller("SupportCtrl", function ($scope, $http) {
$scope.openModal = function (ticketId) {
$http.get('SupportDetail.aspx?ticketId='+ticketId).then(function (response) {
$("#detailBlock").html(response.data);
},
function (error) {
alert("fail");
alert(error);
}
);
}
$scope.openTicketHistory=function(){
var id= $('#tckId').attr('prob');
$http.post('SupportDetail.aspx/ShowHistory',
{ ticketId: id }).then(function (success) {
alert("success")
}
);
}
});
The place is I call the openTicketHistory function inside detailBlock div. And not firing the ngClick event. What can I do?

Check This Out
<html lang="en" >
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Angular Material style sheet -->
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.8/angular-material.min.css">
</head>
<body ng-app="BlankApp" ng-cloak>
<div>
<div ng-controller="SupportCtrl">
<div id="detailBlock">{{myWelcome}}</div>
<md-button ng-click="openModal(5)">Test</md-button>
</div>
</div>
<!-- Angular Material requires Angular.js Libraries -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-aria.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-messages.min.js"></script>
<!-- Angular Material Library -->
<script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.8/angular-material.min.js"></script>
<!-- Your application bootstrap -->
<script type="text/javascript">
/**
* You must include the dependency on 'ngMaterial'
*/
angular.module('BlankApp', ['ngMaterial', 'ngMessages'])
.controller("SupportCtrl", function ($scope, $http) {
$scope.openModal = function (ticketId) {
$http.get('SupportDetail.aspx?ticketId='+ticketId)
.then(function (response) {
$("#detailBlock").html(response.data);
},
function (error) {
alert("fail");
alert(error);
}
);
}
$scope.openTicketHistory=function(){
var id= $('#tckId').attr('prob');
$http.post('SupportDetail.aspx/ShowHistory',
{ ticketId: id }).then(function (success) {
alert("success")
});
}
});
</script>
</body>
</html>
<!--
Copyright 2016-2018 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that can be found in the LICENSE file at https://material.angularjs.org/latest/license.
-->

First, here are some best practices
You should not access the DOM from your controller, don't try to think like Jquery where you have to access the DOM element in order to update it (See conceptual overview chapter from angularjs docs)
Avoid using $scope in your controller, use "controller as syntax instead"
Avoid using $http inside your controller, use an angularjs service instead
As for the solution, you can just use Angularjs's Data binding feature to bind the model (inside the Controller) to the view
$scope.ticket = response.data
in the view:
<div id="detailBlock">{{ticket}}</div>
Here is the link to a working jsfiddle : http://jsfiddle.net/bhjd4kto/25/
EDIT :
if your goal is to display html content inside #detailBlock, you can use angular-sanitize and ng-bind-html directive, here is an example : http://jsfiddle.net/bhjd4kto/45/

Related

AngularJs:Call directive from controller with some values

I have a directive like this
app.directive('pagination',function () {
//custom directive for build pagination
return {
restrict: 'E',
template:function (elem,attr) {
console.log(attr.pageCount);
return 'pagination here';
}
};
})
and its renderd in my html like this
<pagination pageCount="2" currentPage="currentPage"></pagination>
But i want to render this after an http call from my controller
$http.post('/search',searchParams).then(function (response) {
//render `pagination` from here
})
AngularJS normalizes an element's tag and attribute name to determine
which elements match which directives. We typically refer to
directives by their case-sensitive camelCase normalized name (e.g.
ngModel). However, since HTML is case-insensitive, we refer to
directives in the DOM by lower-case forms, typically using
dash-delimited attributes on DOM elements (e.g. ng-model).
Try with ng-if..
<pagination page-count="2" current-page="currentPage" ng-if="showPage"></pagination>
$http.post('/search',searchParams).then(function (response) {
//render `pagination` from here
$scope.showPage = true;
})
(function(angular) {
'use strict';
angular.module('docsTransclusionExample', [])
.controller('Controller', ['$scope', function($scope) {
$scope.name = 'Tobias';
}])
.directive('pagination',function () {
//custom directive for build pagination
return {
restrict: 'E',
template:function (elem, attr) {
console.log(attr.pageCount);
// console.log(attr.pagecount);
return 'pagination here';
}
};
});
})(window.angular);
/*
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-directive-transclusion-production</title>
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="docsTransclusionExample">
<div ng-controller="Controller" ng-init="hid = false">{{hid}}
<pagination ng-if="hid" page-count="2" current-page="currentPage"></pagination>
<button ng-click="hid=true">Click!</button>
</div>
</body>
</html>

ng-repeat doesn't work when HTML is altered under $compile

Directive code:
.directive('replace', function($compile) {
return function (scope, element) {
element.html(element.html().replace("Hej", "Hey!"));
$compile(element.contents())(scope);
}
});
})
HTML
<div ng-controller="GreeterController">
<div replace>Hej <div ng-repeat="e in arr">{{ e }}</div>
</div>
</div>
Controller
app.controller('GreeterController', ['$scope', function($scope) {
$scope.arr = [1, 2, 3, 4];
}]);
Live example
As the title says, ng-repeat doesn't work when I'm using the directive from above on HTML which contains it.
But once I remove that line which uses .replace() command to replace part of HTML then ng-repeat starts working for some reason.
Does anyone know where's the actual problem?
I have tried everything and I still seem to not get it why it doesn't work as it should.
The manipulation can also be done in the compile phase:
app.directive("replace", function(){
return {
compile: function(element){
element.html(element.html().replace('Hej', 'Hey!'));
/*return {
pre: function(scope, element){
element.html(element.html().replace('Hej', 'Hey!'));
}
}*/
}
};
});
The original problem was caused because the linking of the ng-repeat directive was done before the element with that directive is replaced with the replace operation. The watchers associated with the ng-repeat directive then operate on elements that are no longer attached to the visible DOM.
By moving the replace operation to either the compile phase or the preLink phase, the replacing of the element that has the ng-repeat directive is done before the ng-repeat directive is linked. The watchers associated with ng-repeat directive then work with the replaced DOM.
You should let Angular and its change detection cycle do the HTML manipulation for you, instead of directly changing it yourself.
I've edited your example to use scope bindings to achieve what you wanted:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-compile-production</title>
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
</head>
<body ng-app="compileExample">
<script>
angular.module('compileExample', [], function($compileProvider) {
// configure new 'compile' directive by passing a directive
// factory function. The factory function injects the '$compile'
$compileProvider.directive('replace', function($compile) {
return {
link: function (scope, element) {
scope.greeting = 'Hey!';
$compile(element.contents())(scope);
}
}
});
})
.controller('GreeterController', ['$scope', function($scope) {
$scope.test = [1, 2, 3, 4];
$scope.greeting = 'Hej';
}]);
</script>
<div ng-controller="GreeterController">
<div replace>{{greeting}} <div ng-repeat="e in test">{{ e }}</div></div>
</div>
</body>
</html>
<!--
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->
Note: I removed "scope: false" as that is the default behaviour.
EDIT:
Since you must replace HTML in place here's a solution with jQuery:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-compile-production</title>
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous"></script>
</head>
<body ng-app="compileExample">
<script>
angular.module('compileExample', [], function($compileProvider) {
// configure new 'compile' directive by passing a directive
// factory function. The factory function injects the '$compile'
$compileProvider.directive('replace', function($compile) {
return function (scope, element) {
$(element).find( ".translation" ).replaceWith("Hey!");
}
});
})
.controller('GreeterController', ['$scope', function($scope) {
$scope.arr = [1, 2, 3, 4];
}]);
</script>
<div ng-controller="GreeterController">
<div replace><span class="translation">Hej</span> <div ng-repeat="e in arr">{{ e }}</div></div>
</div>
</body>
</html>
<!--
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->
Solved it like this:
.directive("replace", function(){
return {
compile: function(){
return {
pre: function(scope, element){
element.html(element.html().replace('Hej', 'Hey!'));
}
}
}
};
});
Live example

Using Multiple Angular.js Controllers on same DOM

Im pretty new to Angular.js and trying to implement it on my Node.js app.
Ive had success creating an RESTful API using angular for a single controller but now would like to use two or more controllers on a single DOM.
Specifically, I would like to..
1) Use angular to load a global scope for the DOM template containing things like site title, navigation, and metadata, all of which will be loaded into the head, header, and footer. The scope would be pulled using a GET request to my Node server.
2) Use angular to load the scope for a given page. This would be on a case-by-case basis for each page. The simple case being to load the scope into the template.
I have succeeded in doing both (1) and (2) separately, but combining them throws an error.
Here is my complete template (actually loaded in parts by Node):
Head - containing ng-controller="configCtrl" for global configuration scope
<html ng-app="angular" ng-controller="configCtrl" ><head>
<meta http-equiv="Content-Type" content="text/html charset=UTF-8" />
<title>{{context.title}}</title>
<meta name="description" content="{{context.description}}">
<meta name="author" content="{{context.author}}">
<!-- Angular -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
</head><body><div id="wrapper" >
Body - containing ng-controller="testCtrl" for this particular page scope
<div class="container" ng-controller="testCtrl">
<div class="gutter col hidden-xs"> </div>
<div class="content col" >
<div class="py80">
<h1>{{context.test}}</h1>
</div>
</div>
<div class="gutter col hidden-xs"> </div>
</div>
<!-- ANGULAR CONTROLLER FOR THIS PAGE -->
<script src="/public/js/angular/test_controller.js"></script>
Footer - includes the link to controller for global scope
<footer id="footer" ></footer>
</div></body></html> <!-- close tags-->
<!-- ANGULAR CONTROLLER FOR GLOBAL CONFIGURATION SCOPE -->
<script src="/public/js/angular/config_controller.js"></script>
Here is my Angular controller for the "configuration scope"
var app = angular.module('angular', []);
app.controller('configCtrl', function($scope, $http) {
console.log("config controller");
$http.get('/config').then(function(response){
console.log(response.data);
$scope.context = response.data;
});
});
Here is my Angular controller for the page scope
var app = angular.module('angular', []);
app.controller('testCtrl', function($scope, $http) {
console.log("test controller");
$http.get('/test').then(function(response){
console.log(response.data);
$scope.context = response.data;
});
});
I have some server-side controllers returning data back to angular, as mentioned, they each work when used independently but using them together (as shown above) throws the following client-side error:
angular.js:13920 Error: [ng:areq] http://errors.angularjs.org/1.5.8/ng/areq?p0=testCtrl&p1=not%20a%20function%2C%20got%20undefined
at angular.js:38
at sb (angular.js:1892)
at Pa (angular.js:1902)
at angular.js:10330
at ag (angular.js:9451)
at p (angular.js:9232)
at g (angular.js:8620)
at g (angular.js:8623)
at g (angular.js:8623)
at g (angular.js:8623)
Any suggestions?
The problem is you are initializing the app twice. Do this only once:
var app = angular.module('angular', []);
And you’ll be fine. Best practice is to separate that line out into another file entirely (like 'app-initialize.js') and then, you can just do:
angular.module('angular').controller(...);
in all of your files.
var app = angular.module('angular', []);
You're calling this line twice (based on your example) which will create a module called 'angular' twice.
Also, instead of using a controller for the configuration, you can create a factory or service and inject it into any controller that needs it.
(roughly:)
var app = angular.module('someApp', []);
app.controller('testCtrl', function($scope, $http, configFactory) {
$scope.getConfig = function() {
configFactory.getConfig()
.success(function (someConfig) {
console.log(someConfig);
});
}
$scope.getConfig();
console.log("test controller");
$http.get('/test').then(function(response){
console.log(response.data);
$scope.context = response.data;
});
});
app.factory('configFactory', ['$http', function($http) {
var getConfig = function() {
return $http.get('/config');
}
return getConfig;
}]);
Alternatively, you can create a configuration module and pass that as a dependency.
var config = angular.module('config', []).constant('config', { 'something': 2 });
...
var app = angular.module('someApp', ['config']);
...

REST call in AngularJS does not display record

This is my first AngularJS project. I followed this website to create a simple html to display a single record by calling restful services. The rest works with the url "http://localhost:8080/api/seqs/fdebfd6e-d046-4192-8b97-ac9f65dc2009".
Here is my html:
<html ng-app="cgApp" ng-controller="CgseqCtrl">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular-resource.js"></script>
<script src="../js/controller.js"></script>
</head>
<body>
<div>
<hr>
<h2>{{seq.analysisId}}</h2>
<h2>{{seq.library}}</h2>
</hr>
</div>
</body>
</html>
I defined the resource in a service js
//service.js
angular.module('cgApp', ['ngResource'])
.factory('CgseqService', function ($resource) {
return $resource('http://localhost:8080/api/seqs/fdebfd6e-d046-4192-8b97-ac9f65dc2009',
{get: {method: 'GET'}
});
});
The controller:
//controller.js
angular.module('cgApp', ['ngResource'])
.controller('CgseqCtrl', ['CgseqService', '$scope', function (CgseqService, $scope)
{
$scope.getSeq = function(response) {
CgseqService.get(function(data) {
$scope.seq = data;
});
};
}]);
When I started my http server with Node.js and typed the url in the browser, nothing is displayed. What did I do wrong?
Several errors.
You didn't load your factory code. It looks like you only loaded your controller.js (I'm assuming your factory code is in a different file since in your example you commented it as //service.js):
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular-resource.js"></script>
<script src="../js/controller.js"></script>
</head>
np-controller should say ng-controller:
<html ng-app="cgApp" np-controller="CgseqCtrl">
You also never called your $scope.getSeq function:
$scope.getSeq = function(response) {
CgseqService.get(function(data) {
$scope.seq = data;
});
};
You should call $scope.getSeq() somewhere to actually invoke it.

Refresh JSON Data Using Angular

Just finished a Codeacademy tutorial using angular to loop through some JSON data from a URL and display the data.
Would love to know how to implement it so the data would be updated if the JSON data was changing periodically!
I know I need to maybe refresh the http get request,but after that I'm not sure.
If someone could point me in the right direction I would really appreciate it!
Thanks!
services/forecast.js
app.factory('forecast', ['$http', function($http) {
return $http.get('http://json-time.appspot.com/time.json')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}]);
controllers/MinorController.js
app.controller('MinorController', ['$scope', 'forecast', function($scope, forecast) {
var setTimeOut = setInterval(function () {
forecast.success(function(data) {
$scope.fiveDay = data;
});
}, 5000);
$scope.$on('$routeChangeStart', function (scope, next, current) {
if (next.$$route.controller != "MinorController") {
clearInterval(setTimeOut); // clear interval here
}
});
}]);
test.html (view)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Angular -->
<script src="js/shared/angular.min.js"></script>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/bootstrap.min.css">
<!-- Bootstrap JS -->
<script src="js/shared/bootstrap.min.js"></script>
</head>
<body ng-app="myApp">
<div class="container" ng-controller="MinorController">
<div class="row">
<h1>Time JSON Example</h1>
<h2>{{ fiveDay.tz }} </h2>
<h2> {{ fiveDay.hour }} </h2>
<h2> {{ fiveDay.datetime }} </h2>
<h2> {{fiveDay.second }} </h2>
</div>
</div>
<!-- Modules -->
<script src="js/app.js"></script>
<!-- Controllers -->
<script src="js/controllers/MainController.js"></script>
<script src="js/controllers/MinorController.js"></script>
<!-- Services -->
<script src="js/services/forecast.js"></script>
</body>
</html>
You can do it by using setInterval like so.
app.controller('MinorController', ['$scope', 'forecast', function($scope, forecast) {
var setTimeOut = setInterval(function () {
forecast.success(function(data) {
$scope.fiveDay = data;
});
}, 5000);
$scope.$on('$routeChangeStart', function (scope, next, current) {
if (next.$$route.controller != "MinorController") {
clearInterval(setTimeOut); // clear interval here
}
});
}]);
Now your service will call every 5 seconds and rebind your object.
If you go to another screen, then the routeChangeStart event will call for the interval to be cleared.
You can do it on several ways:
You can make http request in loop every few seconds
setInterval(function(){ alert("Hello"); }, 3000);
If you develop server data source you can setup real time connection, using i.e. SignalR or Socket

Categories

Resources