I am developing a mobile application and found that angularjs 1.1.4 has a ngTap directive available replacing standard ng-click. It makes app more robust, so I've decided to replace all my ng-href directive with ng-tap. For this purpose I've created a "go()" function available from $rootScope. The problem is that it can not resolve the url variable.
Here's my code.
$rootScope.go = function (url) {
$location.path(url);
}
and in template:
<a class="niceButtonLikeStyled" data-ng-click="go(/somewhere/var.id/)">{{ var.id }}</a>
Using data-ng-click as ngTap is portable and replaces ng-click if new ngMobile loaded.
My problem seems to be with go() argument (mixing static & variable content ?
Maybe there's the other way of just binding new ng-click to all links.. or simply adding own directive that would take value from ng-href and made the location redirect and attach the ng-tap click event.
AngularJS Expressions for ng-click
When you use ng-click, you're calling an AngularJS expression.
Your current code's expression is this:
go(/somewhere/var.id/)
You need to quote that string:
go('/somewhere/' + var.id + '/')
Other Issues
Another issue with your code: The function go should be in the scope of the controller rather than in the $rootScope:
angular.module('MyModule').controller(
'MyController',
function ($scope, $location) {
$scope.go = function (url) {
$location.path(url);
}
}
);
Here's how your template would look:
<div ng-controller="MyController as mycontroller">
<a class="niceButtonLikeStyled"
data-ng-click="mycontroller.go('/somewhere/' + var.id + '/')">
{{ var.id }}
</a>
</div>
That's the biggest issue with the code, you're using $rootScope instead of putting the variables and functions you need in the scope of a controller where it belongs.
Related
Trying to make a rating directive but I'm stuck at getting rating2 to work. The first rating worked because the rating1 is hardcoded within the controller. But normally I have to get the saved rating from the db, which I'm trying to do with rating2, as u can see the value is fetched but the directive is not appearing.
https://codepen.io/eldyvoon/pen/MbBNLP
<div star-rating ng-model="rating.rating1" max="10" on-rating-select="rating.rateFunction(rating)"></div>
<br>but rating2 is actually there:
{{rating.rating2}}
<star-rating ng-model="rating.rating2" readonly="rating.isReadonly"></star-rating>
Need expert of directive to help.
Initiate rating2 :
function RatingController($http) {
this.rating1 = 5;
this.rating2 = 0; //ADD THIS LINE
var self = this;
it works for me
check here
First of all, I'm not a directive expert but i'm trying to help. I think that when html is first load, the values from db not finish execute and bind into html. The best way is not using directive instead using controller to fetch data from db.
You pass a model without rating2 into your directive and the changes from the parent controller won't affect it, because variable is created afterwards. Adding a watcher in your linker on parent scope will solve the problem;
scope.$parent.$watch('', function(rating){
updateStars();
});
Other solution would be to define a starting value in your controller.
this.rating2 = 1;
Notice that it is bad design to have a scope variable for each rating. It is cleaner to have an array of ratings and you actually do not need the watcher by doing so.
https://codepen.io/hoschnok/pen/LbJPqL
angular controller
function RatingController($http) {
this.ratings = [4];
var self = this;
$http.get('https://api.myjson.com/bins/o0r69').then(function(res){
self.ratings.push(res.data.rating2);
});
}
HTML
<div ng-app="app" ng-controller="RatingController as rating" class="container">
<div ng-repeat="r in rating.ratings">
<div star-rating ng-model="r" max="10" on-rating-select="rating.rateFunction(rating)"></div>
</div>
</div>
The watcher change handler function has parameters reversed:
//INCORRECT parameters
//scope.$watch('ratingValue', function(oldValue, newValue) {
//CORRECT parameters
scope.$watch('ratingValue', function(newValue, oldValue) {
if (newValue) {
updateStars();
}
});
The first argument of the listening function should be newValue.
The DEMO on CodePen
ALSO
The ng- prefix is reserved for core directives. See AngularJS Wiki -- Best Practices
JS
scope: {
//Avoid using ng- prefix
//ratingValue: '=ngModel',
ratingValue: '=myModel',
max: '=?', // optional (default is 5)
onRatingSelect: '&?',
readonly: '=?'
},
HTML
<!-- AVOID using the ng- prefix
<star-rating ng-if='rating' ng-model="rating.rating2"
max="10" on-rating-select="rating.rateFunction(rating)">
</star-rating>
-->
<!-- INSTEAD -->
<star-rating ng-if='rating' my-model="rating.rating2"
max="10" on-rating-select="rating.rateFunction(rating)">
</star-rating>
When a custom directve uses the name ng-model for an attribute, the AngularJS framework instantiates an ngModelController. If the directive doesn't use the services of that controller, it is best not to instantiate it.
In my directive i using appendTo and ng-click inside it:
$("<div>" + "<a href='' ng-click='addIt()' + user + "</a></div>").appendTo '.user-class'
And ng-click doesn't work. Should i use $compile? How to use it in that case?
this code is a part of directive that make dropdown menu from json. There is no option to move this to directive template, so need to find solution how to make 'ng-click' works here.
Like Matthew, I am most curious as to which part(s) cannot be moved out into an external template / internal template function. It doesn't make much sense to me to have to re $compile a directive only to add a ng-click handler.
The senseful way would be to add the ng-click directive to a template. Either an external one, or a function returning a string value in the directive definition object.
Running $compile after the link step has finished is not a good idea performance wise, seeing as how it recompiles the entire DOM element your directive is attached to. Avoid doing so for as long as you possibly can.
.directive('myDir', function () {
return {
template: function (/*element, attrs*/) {
return '<div>{{::user}}</div>';
},
link: function (scope, el, attrs) {
scope.user = 'John';
}
};
});
This would result in the following DOM structure:
<div>
John
</div>
jsbin
Yes you will need $compile , inject $compile in directive and you can do it like this :
var link = $compile("<div>" + "<a href='' ng-click='addIt()'" + user + "</a></div>")(scope);
link.appendto('.user-class');
I'd like to bind a links href property to a variable in my controller but I'd also like to have that url be bound to variables. I'd like to accomplish this using the built in binding and without having to manually watch for changes and reload the url. Is this possible?
// In the controller
$scope.section = 'section1';
$scope.page = 'page1';
$scope.url = 'http://myurl/{{section}}/{{page}}';
<!-- In the template -->
<a ng-href="{{url}}">Page Link</a>
This is a simplification of my actual code. Declaring the url pattern in the template would work but I need to have the url be defined in a string that gets passed in.
Just set the ng-href
<a ng-href="http://myurl/{{section}}/{{page}}">Page Link</a>
In the controller, you don't need to use curly braces expressions.
Replace this:
$scope.url = 'http://myurl/{{section}}/{{page}}';
With this:
$scope.url = 'http://myurl/'+$scope.section+'/'+$scope.page;
And to bind it in your template, use:
<a ng-href="http://myurl/{{section}}/{{page}}">Page Link</a>
So, you can now watch for any changes.
I have a tag inside a directive, click on this anchor should change state of the directive's model variable and refresh the directive view that depends on this scope variable. There are two way to achieve this in Angular:
1)
<my-directive>
<a ng-click="myProperty = 'foo'">bar</a>
</my-directive>
Inside the directive controller:
$scope.$watch('myProperty', function(value) {
myPromise.then(function() { //the promise exists in real code but does not have anything to do with the question itself
updateComponent(value);
});
});
2)
<my-directive>
<a ng-click="handleMyPropertyChange('foo')">bar</a>
</my-directive>
Inside the directive controller:
$scope.handlePropertyChange = function(value) {
$scope.myProperty = value;
myPromise.then(function() {
updateComponent(value);
});
});
Which one is preferred and why?
I prefer the second option. Code belongs in the controller and even a simple assignment is still code.
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.