data-ng-src with if condition - angularjs

I have an image that I display using this:
<img data-ng-src="data:image/jpg;base64,{{selectedReport.reportImage.imageFile.data}}"/>
The above data is fetched from my database.
When the user clicks edit record and selects a new image which is stored in variable imageFile, I want to show this imageFile instead of the record fetched.
How do I use an if condition with data-ng-src?
Individually these work, but i want to apply an if condition where I say, if ImageFile, then
data-ng-src="{{imageFile}}"
else
data-ng-src="data:image/jpg;base64,{{selectedReport.reportImage.imageFile.data}}"
I tried to do like this:
data-ng-src = {{imageFile}} and data-err-src = "data:image/jpg;base64,{{selectedReport.reportImage.imageFile.data}}"/>
But this doesn't work.

I think you should just use a function, declared in your controller to deal with the situation.
In your controller :
$scope.getImage = function (){
return $scope.imageFile || [your_default_image_file];
}
In your HTML, something like :
<img data-ng-src="{{getImage()}}"/>
I hope it helps.

AngularJS views support binary operators
condition && true || false
So your img tag would look like this
<img data-ng-src="{{ imageFile != '' && imageFile || 'your-default-image' }}"/>
Note : You could use any condition to know if imageFile exists or has a value.
Note 2 : the quotes (ie 'your-default-image') are important here. It won't work without quotes.

Related

ng-tags-input not working correctly with autocomplete

I'm adding tag by selecting from list (which is populated using $http request). The tag is added but the text which I have typed that remains there with ng-invalid-tag class.
ScreenShots
1) Initially,
2) Typing 3 letters to get HTTP Call.
3) Now after selection of first Skill "Angular Js'.
4) It shows that .input.invalid-tag is enabled. And which doesn't clear the placeholder.
My Input Tag is as below.
<tags-input ng-model="employerMyCandidatesCtrl.skillList" placeholder="Skills..."
replace-spaces-with-dashes="false"
add-from-autocomplete-only="true"
display-property="skillName"
on-tag-added="employerMyCandidatesCtrl.addTagToSkillData($tag)"
on-tag-removed="employerMyCandidatesCtrl.removeTagFromSkillData($tag)">
<auto-complete
source="employerMyCandidatesCtrl.loadSkillData($query)"
displayProperty="skillName" debounce-delay="500"
min-length="3">
</auto-complete>
</tags-input>
Controller Code is as below.
vm.skillList = [];
vm.loadSkillData = function(query) {
return EmployerServices.getAllSkillsPromise(query); // $http call.
};
vm.addTagToSkillData = function(tag) {
if (_.findIndex(vm.skillList, tag) < 0) {
vm.skillList.push(tag);
}
};
vm.removeTagFromSkillData = function(tag) {
var ind = _.findIndex(vm.skillList, tag) > -1 ? vm.skillList.splice(ind, 1) : '';
};
Is any configuration mistake I'm doing?
There are 4 attributes for onTagAdding, onTagAdded, onTagRemoving, onTagRemoved so the basic difference between the attributes ending with adding compared to those ending with added is
Adding suffixed tags are expecting a boolean which when true will be added
or removed based on the tag used.
But onTagAdded/Removed already adds the tag, before the function is called hence we can do some additional logic or else strip the ng-model of the added value or add back the removed value(not very easy).
Check the below JSFiddle to see the four attributes in action here
I have made a custom service to supply the data, so the final answer to your question will be to use the appropriate attribute (onTagAdding, onTagAdded, onTagRemoving, onTagRemoved) based on your usecase. From the above code, I think we need not write onTagAdded, onTagRemoved since its done automatically.

Using Protractor to check for a value that is visible

I have a section of code that displays two different ways based on a condition. In both ways, there is a value that I want to check:
user.name
This is displayed on the page like
<span ng-show="showusername && something > 3">{{user.name}} (other stuff here)</span>
<span ng-show="showusername && something <= 3">{{user.name}}</span>
My problem is, this is used elsewhere on the page as well, and the protractor piece can't seem to find the binding if I use by.binding('user.name'), it finds multiple, and displays
Expected '' to equal 'Joe Smith'
You can filter out the visible elements only:
var visibleUserNames = element.all(by.binding("user.name")).filter(function (elm) {
return elm.isDisplayed().then(function (isDisplayed) {
return isDisplayed;
});
});
expect(visibleUserNames.count()).toEqual(1);
expect(visibleUserNames.first().getText()).toEqual("Joe Smith");

Strange bug with ng-repeat and filter

I'm using NodeJS, ANgularJS, and MongoDB with mongoose
Here is my model :
var PostSchema = new mongoose.Schema({
nomReseau : String,
corps : String,
etat : String,
section : String
});
I got a function that change the attribute etat:
$scope.passer = function(index){
var post = $scope.posts[index];
post.etat = "enCours";
Posts.update({id: post._id}, post);
$scope.editing[index] = false;
}
I'm using a ng-repeat for show object in my database :
<ul>
<li ng-repeat="post in posts ">
<p>
<a ng-show="!editing[$index]" href="#/{{post._id}}">{{post.corps}}</a>
</p>
<button ng-show="!editing[$index]" ng-click="passer($index)">Passer</button>
</li>
</ul>
I can see all post in my database and when I click on the button this works perfectly the attribute etat change and all is fine.
But when I add a filter in the ng-repeat like this :
<li ng-repeat="post in posts | filter:{ etat:'aTraiter'} ">
The filter works great I have all post with the attribute etat:'aTraiter'
But if I click on my previous button and change the attribute etat nothing change and I try with other functions they all work wihout the filter but when I put it nothing work.
The problem is that $index will change if less data is shown (because you're filtering). you could use directly post variable
ng-click="passer(post)"
and your function should be something like
$scope.passer = function(post){
post.etat = "enCours";
Posts.update({id: post._id}, post);
var index = $scope.posts.findIndex(function(p) { /* comparison to get original index */ }); /* keep in mind findIndex is not supported on IE, you might want to use filter or for loop instead) */
$scope.editing[index] = false;
}
you could handle editing in the post variable directly. So in your passer function you can do this
post.editing = false;
and in your view
ng-show="!post.editing"
this way you won't use $index and you will prevent all issues with being updated by filters
There are bugs in AngularJS v1.4 where in certain situations the ng-repeat breaks. I upgraded to v1.6 and it went away.
Do you have any controllers/services that access $scope.editing? If so, you might be setting the $scope.editing[$index] equal a previous state where it wasn't equal to false. You may also want to consider that you are assuming $scope.editing[$index] is going to be a boolean. if it has any other type such as string or number then it will evaluate to true.
Otherwise none of your results have the attribute etat equal to 'aTraiter' so they aren't showing. Have you verified that any of them actually do have etat equal to 'aTraiter'. You might be changing that value somewhere else. Possibly from the Passer function

How do I compare with a string in ng-class?

This line doesn't seem to work for me.
Sort By: Alphabetical
Do I have to escape 'title' in orderProp == 'title' somehow?
in the controller I have
...
$scope.orderProp = 'title';
$scope.setOrder = function(sortBy){
$scope.orderProp = sortBy;
}
...
Thank you
Update: Using v1.3.0-beta.17
Adding ng-class="{active:orderProp=='pagetitle'} to
Alphabetical
throws an error
"Error: [$parse:syntax] http://errors.angularjs.org/1.3.0-beta.17/$parse/syntax?p0=undefined&p1=not%20a%20primary%20expression&p2=null&p3=%7Bactive%3AorderProp%3D%3D&p4=%7Bactive%3AorderProp%3D%3D
Sorry for the way I present the error but I just started angular last week and don't know a better way
Update 2:
error seems to be coming from = == ===. I tried > and no error occured. Is there an alternative syntax to like eq?
Update 3 with solve
I mapped each string to an int pagetile->1 code->2 + data-ng-class="{active:orderPropIdx==1};"
Inside the controller I just do if pagetitle set active:orderPropIdx to 1 and so on
Maybe this is a bug in angular 1.3
As is stated in the comments, your class name should be surrounded by single quotes.
ng-class="{'active': orderProp == 'title'}">
This comparison is case sensitive.
Had the same issue when using ng-class. It refused to dynamically compute the class attribute even though the expression was successfully calculated.
And here is the workaround I've used for the ng-class statement:
Sort By: Alphabetical
instead of ng-class="{active: orderProp == 'title'} I've switched to class="{{orderProp == 'title' ? 'active' : ''}}"
I resolve in this way; 'ClassName':'{{Value}}'=='StringtoCompare', ...
ng-class="{ 'btn-danger' : '{{datasource.difficoltaRicetta}}'=='Difficile', 'btn-warning' :'{{datasource.difficoltaRicetta}}'=='Intermedia', 'btn-success' : '{{datasource.difficoltaRicetta}}'=='Facile'}"
I mapped each string to an int pagetile->1 code->2 + data-ng-class="{active:orderPropIdx==1};" Inside the controller I just do if pagetitle set active:orderPropIdx to 1 and so on
Maybe this is a bug in angular 1.3
This is for people coming to this answer looking for the solution with [ngClass].
<a [ngClass]="{ active: selectedValue === 'foo bar' }"> FooBar </a>
This would result in adding class="active" to the anchor element when the variable selectedValue is given the value "foo bar".
The syntax for ng-class can be quite confusing sometimes. Try this.
ng-class="{true: 'active', false: ''}[orderProp === 'title']"
Include square brackets after the curly braces. Inside the square brackets, you can declare any expression, and declare your results (true/false) and the corresponding classes you want to apply (active). And be sure to use '===' in your expressions, signifying you want orderProp to be exactly equal to what you are comparing it against.

Multiple $interpolation symbols in AngularJs

I am rather new to AngularJs, but I have a specific need for a more complex, conditional template using multiple interpolation symbols. I am using the same example as in https://docs.angularjs.org/api/ng/service/$interpolate .
I need something like:
[[ {{greeting}}, {{name}} || Hello, {{name}} || Hello, stranger ]]
This should be interpreted as a multiple conditional template, showing the first fragment if both $scope.greeting and $scope.name are defined, the second one if only $scope.name is defined, and the third one otherwise.
The idea is that within symbols [[ ]] the fragments between a || symbol are interpolated using the standard interpolation symbols with AllOrNothing, proceeding from left to right until the first one succeeds, and making sure that the last one always succeeds.
I know that this can be done with something like
<span ng-if='greeting && name">{{greeting}}{{name}}</span>
<span ng-if='name && !greeting">Hello, {{name}}</span>
<span ng-if='!name">Hello, stranger</span>
but this solution is extremely cumbersome, requires to determine which complex set of boolean expressions makes sure that only one span is shown, and adds spurious spans to the DOM just because you need a place for the ng-if directives.
Thank you for all you can suggest.
You can write your own filter to handle this situation specifically. If you want something a little more reusable, in regards to conditional output, you could make an a kind of ternary filter. Here's one called iif (named as such to prevent eval errors we'd get if we called it just if):
.filter('iif', function() {
// usage: {{ conditionToTest | iif:truevalue:falseValue }}
// example: {{ iAmTrue | iif:'I am true':'I am false' }}
return function(input, trueValue, falseValue) {
return input ? trueValue : falseValue;
};
})
Use it like this in your example:
{{greeting | iif:greeting:'Hello'}}, {{name | iif:name:'stranger'}}
You can certainly specialize it further, if that's too verbose:
.filter('valueOrDefault', function() {
return function(input, defaultValue) {
return input || defaultValue;
};
})
Then your template looks like:
{{ greeting | valueOrDefault:'Hello' }}, {{name | valueOrDefault: 'stranger'}}
And so on.
The interpolator should be able to handle it.
<p>{{ greeting || 'Hello' }}, {{ name || 'Stranger' }}.</p>

Resources