Combining of angular-ui-bootstrap radio button and angular-translate directives - angularjs

I'm using angular-ui-bootstrap radio button btn-radio directive together with the angular-translate i18n translate directive
The combination of both directives in the <label> element makes the btn-radio failing.
I created a plunkr to show the btn-radio behaviour
I know there are some issues sharing multiple directives on one dom element and a workaround could be to put the translate directive on a sub span element, or using the translate filter.
So, my question is: is there a way to make these both directives work on the same element?

My mother tongue is Korean, not English. so, my english is not good.
cause : conflict bootstrap ui and translate library with html element attribute
solution :
not using translate with element attribute
so, remove element translate attribute.
add function to controller for translate language options.
ex)
$scope.translate = function(id)
{
return $translate.instant(id);
};
translate using function
ex)
<label class="btn btn-primary" ng-model="radioModel" btn-radio="'Left'">{{translate('BTN_A')}}</label>
demo : http://plnkr.co/edit/TPwTan2dSmMVQbNtxpgg?p=preview
test with blue button.

I just run into the same problem and found a simpler solution without the need to add a function in the controller, but simply using the filter:
<label class="btn btn-primary" ng-model="radioModel" btn-radio="'Left'">{{'TRANSLATION.KEY' | translate}}</label>

Related

Using directives as part of angular-translate's translate-values, how to compile?

I am in the process of internationalizing a website and have come across a sticking point with angular-translate.
Suppose I have a translationProvider for english supplying the following text:
"example.message": "I need a {{link}} or {{customDirectiveOutput}} to render directives in me"
"link.text": "this link"
I am now trying to get some HTML into those two placeholders by doing something like the following:
<div translate="example.message"
translate-values="{
link: '<a ui-sref=\'stateName\'>{{ \'link.text\' | translate }}</a>'
customDirectiveOutput: '<span my-custom-directive=\'vm.object\'></span>'
}">
</div>
Where ui-sref is from the ui-router and adds an attribute like href="/path/to/my/state", and my-custom-directive places inner html inside the span sort of like this:
<span my-custom-directive='vm.object'>
<span class='foo'>{{vm.object.foo}}</span>
<span class="bar">{{vm.object.bar}}</span>
</span>
The link tag I can "cheat" around by just hard-coding the href onto the a tag and that isn't so bad to duplicate the /path/to/state, though I'd prefer not to.
The custom directive, however, is conditional on its output so I can't just cheat the output into the translate-values
I've tried doing something in the controller for the page like
$scope.value = vm.getValue();
var element = $compile('<span my-custom-directive="value"></span>')($scope);
return element[0].outerHTML;
But this unfortunately creates an infinite digest loop. I feel like this is the right "path", having some JS pre-compile the fragment I need to insert into the translation, but I'm stuck as to how to accomplish that!
How can I insert angular-compiled HTML with directives attached into a translated string?

Carry over attributes from directive to sub-element

I've got a directive that renders a simple searchbox - its HTML looks as follows:
<div class="search input-group">
<input type="text"
ng-model="text"
ng-change="onChange()"
placeholder="Search here..."
class="form-control">
<span class="input-group-btn">
<button class="btn btn-default glyphicon glyphicon-search"></button>
</span>
</div>
All is well and working, I'm able to use it like this:
<searchbox ng-model="search" />
However, now I would like the searchbox to have autofocus in some cases, and in some cases not, for that, it would be neat to just be able to do:
<searchbox ng-model="search" autofocus />
and have that result in having the autofocus attribute carried over to the <input> tag within the directive. Is this possible? How would I go about doing that? Is there a way to carry over specific attributes over to a specific sub-element?
This is a way: from your directive's link function, read the autofocus attribute and, if it is defined, write it to the <input> using DOM manipulation. (DOM manipulation is OK inside the link function):
link: function(scope,elem,attrs) {
if( angular.isDefined(attrs.autofocus) ) {
var inp = elem[0].querySelectorAll('input');
inp[0].setAttribute('autofocus','autofocus');
}
}
A fiddle demonstrating the principle: http://jsfiddle.net/5yhp2xa0/
Possible catch: I am not sure if HTML's autofocus would work for templates that are inserted to the page "later" (i.e. after Angular route change, when a ng-if is shown etc). If this is the case, then a different solution should be used (could be easy, just call inp[0].focus() instead of inp[0].setAttribute('autofocus','autofocus');).
Since the title of the question is "Carry over attributes from directive to sub-element", let me address the general issue as well:
Attributes are not transferred automatically
If the attribute is non-directive, then techniques similar to the answer above can be used, i.e. manipulate the DOM from the link function. Things can get more complex if the attribute value is dynamic, but the general idea is the same.
If the attribute is a directive things are more difficult. Most probably you will have to use the compile function and manipulate the template of the DOM. In this case however, I would prefer to make the directives cooperate directly using the require configuration, especially with the optional modifier, e.g. require: '?otherAttributeDirective'. Of course this is possible only if you control both directives.
You can use the tab index. I m listing some of the behaviors of tab index as under
The tabindex value can allow for some interesting behaviors .
If given a value of "-1", the element can't be tabbed to but focus can be given to the element programmatically (using element.focus()).
If given a value of 0, the element can be focused via the keyboard and falls into the tabbing flow of the document.
Values greater than 0 create a priority level with 1 being the most important.
Or you can use following javascript code for that.
document.getElementById('txtId').focus();
I would do that programmatically. It feels like you are asking too much of angular to carry the attributes in automatically. The attributes of the directive are available as arguments to the link and compile functions, it should be easy to use the directive template to apply the attribute inside when it's on the outside.
For example, try this:
... directive code
link: function(scope, elem, attrs) {
console.log(attrs.autofocus);
}
You can check the value of autofocus from the attrs like that

Angularjs ui-bootstrap btn-checkbox conditional styling

Would like to use btn-checkbox in place of all my checkboxes on a form. I am looking for the syntax to make a generic reference to the value of the bound property from within the attributes, in this case ng-class.
<button type="button"
ng-class="{true: 'btn btn-success',
false:'btn btn-checkbox-off'}
[vm.csrMain.doubleAggregate]"
ng-model="vm.csrMain.doubleAggregate"
btn-checkbox btn-checkbox-true="true" btn-checkbox-false="false">
DOUBLE AGGREGATE
</button>
( using ctrl as vm syntax ) The code above works, but I want to make a generic reference to the value of the ng-model in the brackets where I am hard coding the bound property [vm.csrMain.doubleAggregate] something like [ng-model.$value]
Tried to do a plunker here. Not sure why I can't get the btn-checkbox behavior I get successfully in the code above. If someone could guide me on that as well I'd appreciate it as this my first shot at a plunk from scratch plunker

AngularJS + Twitter Popover: Content Iteration

I'm using twitter bootstrap with a popover and got a AngularJS scoped variable to appear correctly. The below works.
(data-content="{{notifications[0].user}} shared {{notifications[0].user_two}}'s records")
When I add the following
(data-content="<b>{{notifications[0].user}} shared {{notifications[0].user_two}}'s records</b>")
No errors show up, but all of the {{}} no longer render.
So I tried this as a test of sorts
(data-content="<div ng-repeat='item in notifications'>test {{item}} <br/><hr/></div>")
Much like the last example, I see the "test" but not the {{item}}. And the "test" only show s up once, even though the notifications had three elements. When I look at the DOM there's this
<div class="popover-content">
<div ng-repeat="item in notifications">you <br><hr></div>
</div>
I've also tried just creating a directive to iterate through the array and make the output I want, but my attempt to set data-content equal to a directive have been failures. The examples I've found elsewhere I'm confident would work, but I just wanted to confirm before I begin implementing something like this (http://tech.pro/tutorial/1360/bootstrap-popover-using-angularjs-compile-service) or (Html file as content in Bootstrap popover in AngularJS directive) that I'm not missing a straightforward fix to the problem I outlined above that would not require me creating a directive.
Edit:
Plunkr Url http://plnkr.co/edit/VZwax4X6WUxSpUTYUqIA?p=preview
html might be breaking it, try marking it as trusted html using $sce
How do you use $sce.trustAsHtml(string) to replicate ng-bind-html-unsafe in Angular 1.2+
$scope.html = '<ul><li>render me please</li></ul>';
$scope.trustedHtml = $sce.trustAsHtml($scope.html);
<button ... data-content="trustedHtml" ...> </button>

AngularJS required radio buttons needs two click events to be valid

I have a very simple form where a radio button is required to be selected in order for a form to be valid. The radio buttons are generated by ngRepeat.
As you can see from this fiddle, while the desired behavior is that when the radio button is clicked for the first time, that should validate the form (being the only element), however notice that it takes an additional click (on the same radio button or any other) to validate the form:
http://jsfiddle.net/Xsk5X/3/
What am I missing?
All the other solutions are work-arounds: All you have to do is remove the name attribute, when you use the ng-model attribute you don't need it and they conflict.
Specifying the name causes Angular to get confused because it changes the value once for the angular model and another time for the form element name.
I had this problem because a colleague had copied the radio buttons in the same page and hidden them for temporary reference, so duplicate radio inputs with the same name
Try adding the ng-click attribute to your radio button input.
Credit to Manny D for noting this first. Yes, this is a little hackish, but it works. E.g.,
<input type="radio"
name="groupName"
ng-model="editObject.Property"
ng-value="someValue"
ng-click />
The reason why this is breaking - is because you're setting all radio boxes to be required. As a result, depending on how you write it - angularjs is saying it's invalid because not all have been selected at some point.
The way around this is to do something like the following:
Using checkboxes and required with AngularJS
(check the 1st and 2nd answers). This will resolve your problem.
Seems like an AngularJS 1.0.3 $scope.$apply update problem.
Tested your exact Fiddle in 1.0.2 (check it out yourself) and it works the way you expect it too.
It doesn't seem like there's anything wrong with your code, just that $scope.$apply(or $digest) isn't working as expected on the first select.
A very simple fix is to force the $scope to also update on every select, try changing the following line of code in your form:
<p>Favorite Beatle</p>
change it too:
<p>Favorite Beatle: {{name}}</p>
And you will see how myForm.$invalid is updated even after the first click.
I would try it out with the latest AngularJs version and let us know if that happens there too.
Another solution I can think of it setting the default selected radio, which will cause myForm.$invalid to be false from the beginning. you can do this by adding the following line in your controller code:
$scope.name = "John";
or any default name you want.
Some times the $digest cycle dosen't $apply(fn) because you have two o more instances.
For fix this you need $apply this trick manually, so put this in your directives:
angular.('myApp',[])
.directive('ngRadioExtend', ['$rootScope', function($rootScope){
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, iElm, iAttrs, controller) {
iElm.bind('click', function(){
$rootScope.$$phase || $rootScope.$apply()
});
}
};
}])
and use it as:
<input type="radio" name="input_name" ng-model="some" value="F" ng-required="true" ng-radio-extend>
<input type="radio" name="input_name" ng-model="some" value="M" ng-required="true" ng-radio-extend>
DONE it's the correct way!
The problem of the scope not getting updated still occurs in 1.1.5
A simple work around is to just add
<span ng-show="false"> {{name}} </span>
Fiddle: http://jsfiddle.net/jonyschak/xaQJH/
For IONIC v1,
add name="" to prevent ionic auto-generate attribute name.
Then, I can change the selected item with only one click.
<ion-radio class="label-ticket"
ng-repeat="topic in vm.listTopic track by $index"
ng-value="topic"
ng-model="vm.topicSupport"
name="">
{{ topic.title }}
</ion-radio>

Resources