ng-show binding to string expression in angular - angularjs

Is there a way to bind a ng-show expression to a string which contains the bind expression itself?
For Instance:
field={};
field.a=true;
field.showExpression='a == true';
<input ng-show="field.showExpression">
I´ve tried <input ng-show="{{field.showExpression}}"> as well, but none of them seems to work.
I want the bind to stay active, so that when the field.a object changes from true to false the expression gets evaluated again, hiding the input.
Just as background, i´m trying to implement dependant dropdowns, so my showExpressions should be of form field.showExpression='maindropdownValue!=null', and whenever the maindropdown which will be bound to the maindropdownValue gets selected the second one gets displayed.
I´m using angular 1.0.8

showExpression is evalued as a String not as a JS code. You have to use a function instead.
$scope.isTrue = function() {
return $scope.field.a; // or a more complex check
}
//
ng-show="isTrue()"
if you only have to check for a boolean, you can check var directly in the view:
ng-show="field.a"
If you really want to use eval, this is what you want:
ng-show="$parent.$eval(field.showExpression)"
link: http://docs.angularjs.org/guide/expression

Related

Angular scope variable update not reflected in UI

We are working on an HTML page which makes use of a Bootstrap tooltip on a certain <span> tag. For those who have not heard of tooltip, it is a popup of sorts which appears when hovering over the element to which it is attached. Here is a screenshot showing the <span> in question, and what happens on hover:
The premise behind adding the tooltip was that in the event that we truncate the text, the tooltip would provide an option for viewing the entire text.
However, we would now like to condtionally show the tooltip only when there is no ellipsis in the text. We defined the tooltip-enable property in the <span>:
<span uib-tooltip="{{someName}}" tooltip-placement="right" tooltip-enable="{{showToolTip}}">{{someNameShortened}}</span>
The key thing here is tooltip-enable="{{showToolTip}}", which binds the property to a scoped variable in the controller for this page. And here is the relevant (and abbreviated) controller code:
mainApp.controller('repoListController',['$scope', '$rootScope', ...,
function($scope,$rootScope, ...) {
$scope.showToolTip = false;
var repositoryList= function(){
repositoryService.getRepositoryList(function(data) {
var repoList = data;
repoList.shortenedDisplayName = repositoryService.getShortRepoName(repoList.repoName, DISPLAY_NAME_MAX_LENGTH);
// if the repository's name be sufficiently large (i.e. it has an ellipsis)
// then show the tooltip. Otherwise, the default value is false (see above)
if (repoList.repoName.length > DISPLAY_NAME_MAX_LENGTH) {
$scope.showTooltip = true;
}
});
}
repositoryList();
}]);
Based on the research I have done, the common solution for why a change to a scoped variable is not reflected in the UI is to run $scope.$apply(), or some variation on this. Running apply(), as I understand it, will tell Angular JS to do a digest cycle, which will propagate changes in the scope to the UI. However, trying to do an apply() from the code which toggles showToolTip resulted in errory. I inspected the value of $scope.$root.$$phase while running the code which updates the showToolTip variable, and the phase was digest.
So now I am at a loss to explain this. If the code is already in a digest, then why would changes not be reflected in the UI? Also, if the code is already in digest, then how could I force Angular to sync the changes to the UI?
Two things need fixing...
Don't use string interpolation for your boolean showToolTip
<span uib-tooltip="{{someName}}" tooltip-placement="right"
tooltip-enable="showToolTip">{{someNameShortened}}</span>
JavaScript variables / properties are case sensitive. In your getRepositoryList handler, you have $scope.showTooltip. It should be $scope.showToolTip (two capital "T"s)
Crappy Plunker demo ~ http://plnkr.co/edit/W7tgJmeQAJj0fmfT72PR?p=preview

django-autocomplete-light and angular: how can angular get the value selected

Using django-automcomplete-light V3 and angular on a non admin page.
Using the widget autocomplete.ModelSelect2
Where is the selected value stored? Using firebug, it's not in a new hidden html element and if i attempt to watch the original (now hidden) select element, it's value never changes if I change the selected value in the autocomplete widget.
How can angular watch/read this value?
Update:
As #visegan below points out you can use jquery syntax to get the value but for some reason you can't watch it.
i.e. this watch never gets triggered:
$scope.$watch(function(){
return $('#id_field').val();
},
function(newVal, oldVal){
console.log('current %r', newVal);
$scope.models.foo=parseInt(newVal);
});
Well I have just tried with my project and it was pretty straight forward:
$('#id_field').val()
To be honest, I am also not sure where exactly does the value come from.
As for the change watcher: autocomplete light now uses select2 component, which is apparently a bit problematic with angular.
There are two approaches that works: first one is to add more jquery:
$('#id_field').change(function() {alert('changed')});
This I have tested. The other approach is to do it somehow natively. Look at Select2 event handling with Angular js

Angularjs Bootstrap UI tooltip scope preventing watch from firing

I'm having an issue with a $watch that is really just boggling my brain. I'm almost certain that it is somehow a scope issue. Here's the basics. I'd like a tooltip on a span surrounding a checkbox and it's label so that the tooltip activates on hover over the checkbox or label. something like this.
(note:I've added the {{values.isChecked}} just to watch the values in the two different scopes)
HTML
{{values.isChecked}}
<span tooltip-placement="right" tooltip="This is my tooltip">
<input type="checkbox" id="myCheckbox" ng-model="values.isChecked">
<label for="myCheckbox"> My Checkbox</label> {{values.isChecked}}
</span>
from angular controller
$scope.values.isChecked = true;
$scope.watch("values.isChecked",function(newValue,oldValue){
alert("Made it to the watch");
}
The most odd behavior is that my watch catches the transition of the value from true to false. But does not catch the transition from false to true. I can click it several times and it will make it to the watch going from true to false, but not false to true. If it catches the true to false, and then catches true to false again, well, it HAD to have changed from false to true in order to trigger the watch again. I know the value is actually changing, the two places wehre I added it to the page via {{values.isChecked}}, both show the values change as expected, it's just not firing my watch when I CHECK the box. only when I UNCHECK it.
All my code is on a different box on an isolated network, so I can't actually copy and paste any, so tried to just type in the relevant stuff.
Also if I just take out the Span that has the tooltip on it, it works just fine. I'm aware that bootstrap UI's tooltip does create a new scope. so suspect that, but don't know why it works for one transition, but not the other.
I have even gone as far as capturing the scope inside the tooltip and adding my watch there such as...
myChildScope = angular.element('#myCheckBox').scope()
myChildScope.$watch("values.isChecked",function(newValue,oldValue){
...
It behaves incorrectly, the exact same way. Also behaves the exact same (bad) way if I try to add an ng-click or ng-change to the checkbox element.
Two things to try, I'm not sure how your code is setup but for issues of a watch not catching things when you think it should, generally one of these will work.
$scope.watch("values.isChecked",function(newValue,oldValue){
alert("Made it to the watch");
}, true);
The true tells it to compare for object equality using angular.equals instead of comparing for reference equality. Since it's a boolean primitive... probably more of what you want to use.
The other option, which may or may not help in your case, it to use
$scope.watchCollection("values",function(newValue,oldValue){
alert("Made it to the watch");
});
And see if anything in the values object changes.
Also, you could change isChecked to an object,
$scope.isChecked = { checked: false }
and $watch the object rather than the boolean itself.

Ruby: Setting select model value not working via AngularJS binding

I have a situation where I'm setting the object on a select element externally (an edit modal dialog). When I set the scope variable value the select control just loses it's value instead of selecting the equivalent item (like the object with the same id).
I wonder if it's a different ng-option value I need, there seem to many ways of populating it which I don't understand from the documentation. I'm using the basic type:
<select ng-model="color" ng-options="c.name for c in colors"></select>
I've created a similar situation here. I need clicking the button to set the proper value in the select drop down.
AngularJS compares for reference rather than for equality. When you make that, AngularJS doesn't find any equivalent object in $scope.colors, and then sets the list to an empty value :
$scope.setColor = function() {
$scope.color = {id:12,name:'white',shade:'light'};
};
Instead, you can simply make that, like in this fiddle :
$scope.setColor = function() {
$scope.color = $scope.colors[1];
};

Angular - Form validation issues when using form input directive

I have been trying to build a form input directive which will generate a form input based on the model and the model attributes .
For example,
if the field is name and type is text, the directive will return a input html control,
if the field is a list, then it will return a select box
and so on
These inputs are generated using ng-repeat in the view. The inputs are bound to the model in the scope. This is working fine. However, the form validation fails; i.e if the input controls are invalid, the main form still shows the form is valid.
I have put up a simple plunkr to illustrate the issue - http://plnkr.co/edit/R3NTJK?p=preview
NOTE : I have actually nested the form, as the input name field is also dynamically generated from the scope model.
I have been trying to a get hold on this from the past 2 days and this is really driving me nuts.
I m not sure if I m missing something.
I would really appreciate if some one could help me out with this.
Update:
Use the following link function:
link: function linkFn(scope,elem,attr){
var jqLiteWrappedElement =
angular.element('<input type="url" name="socialUrl" ng-model="social.url">');
elem.replaceWith(jqLiteWrappedElement);
$compile(jqLiteWrappedElement)(scope);
}
Plunker.
For reasons I don't understand, the replaceWith() must be executed before the call to $compile. If someone can explain why this is so, we'd appreciate it!
Update2: in the comments below, Artem mentioned that the DOM must be modified before the linking function is called, so this also works:
var myElem = angular.element('some html');
var linkFn = $compile(myElem);
element.replaceWith(myElem);
linkFn(scope);
Original answer:
Instead of the link function, just use a template in your directive:
template: '<input type="url" name="socialUrl" ng-model="social.url">'

Resources