how to deal with ng-src with invalid url in ng-repeat - html

I would like to show the picture of a user if there is a user in my object list (profileList), and default/error as defaultProfile.png when no user is found ({{item.userProfile}} is null)
I have searched for similar approaches such as
angularjs: ng-src equivalent for background-image:url(…)
and
empty ng-src doesn't update image
My approach to this problem is:
<div ng-repeat="item in profileList">
<div>
<img src='assets/img/defaultProfile.png' data-ng-src="http://example.com/{{item.userProfile}}.jpg" onerror="this.src='assets/img/defaultProfile.png'" />
</div>
<div>
I am able to show error photo however I am still getting error 500,
GET http://example.com/.jpg 500 (INTERNAL SERVER ERROR)
How to avoid getting http://example.com//.jpg?
Thanks a lot

Your current issue is ng-src is still compiled and evaluated to an invalid url when userProfile is undefined.
A simple solution is to use ternary and check for userProfile before deciding with url should be rendered:
<img ng-src="{{ item.userProfile ? 'http://example.com/' + item.userProfile + '.jpg'}} : 'assets/img/defaultProfile.png'" />
It will guarantee that you will always fetch the default image unless item.userProfile is available.

One approach is to use ng-if and ng-hide:
<div ng-repeat="item in profileList">
<div>
<img ng-if="item.userProfile"
data-ng-src="http://example.com/{{item.userProfile}}.jpg" />
<img ng-hide="item.userProfile"
src="assets/img/defaultProfile.png" />
</div>
<div>
When item.userProfile exists, show the ng-src and hide the default otherwise vice versa.

It works.
ng-show
will run no matter {{item.userProfile}} is null or not.
By changing it to
ng-if
Below code is working:
<div ng-repeat="item in profileList">
<div>
<img ng-if="item.userProfile"
data-ng-src="http://example.com/{{item.userProfile}}.jpg" />
<img ng-if="item.userProfile == null"
src="assets/img/defaultProfile.png" />
</div>
note that my profileList is:
$scope.profileList = {userProfile = null}
Thanks a lot

Related

State in React component not setting data when the browser (tab) is refreshed

I have this simple react component that gets data from an API (fetch called in UseEffect), and displays it using HTML. When I refresh the page, all html disappears from the page and it goes blank. What's peculiar is that when I instead make some changes in the code editor and let react autoupdate the page after saving, it displays everything just fine.
Here's the code snippet for the component:
export function AgentCard(props){
console.log("agentcard function");
const [agentData,setAgentData] = useState({});
useEffect(()=> {
console.log('running useEffect')
axios.get('https://valorant-api.com/v1/agents/').then(res=>{
var agentRes;
for (const agent of res.data['data']){
if (agent['displayName'] === props.agentName){ agentRes = agent}
}
setAgentData(agentRes);
console.log(agentData)
})
},[])
return(
<div className='AgentCard'>
<h2>{agentData['displayName']}</h2>
<img src={agentData['displayIcon']}></img>
<div className='AgentCardBody'>
<div className='AbilitiesBar'>
<img src={agentData['abilities'][0]['displayIcon']} className='AbilitiesIcon'></img>
<img src={agentData['abilities'][1]['displayIcon']} className='AbilitiesIcon'></img>
<img src={agentData['abilities'][2]['displayIcon']} className='AbilitiesIcon'></img>
<img src={agentData['abilities'][3]['displayIcon']} className='AbilitiesIcon'></img>
</div>
</div>
</div>
)
After some digging and logging, what I found is that when I refresh the page, the state (agentData), is saved to this:
https://imgur.com/a/QzfIdpm
and get the following error in the console:
https://imgur.com/a/H7gLiTQ
But once I make any change to the editor and let react autorefresh, the logs show that the state agentData has the right data object pulled from the API.
Also, this only happens when I have the following part of the code running
<img src={agentData['abilities'][0]['displayIcon']} className='AbilitiesIcon'></img>
<img src={agentData['abilities'][1]['displayIcon']} className='AbilitiesIcon'></img>
<img src={agentData['abilities'][2]['displayIcon']} className='AbilitiesIcon'></img>
<img src={agentData['abilities'][3]['displayIcon']} className='AbilitiesIcon'></img>
Once I comment this out, everything displays correctly even after a browser refresh
I know the way I've posed the question is confusing, but I'm new to front end development and don't really know what I'm supposed to look for here.
Probably because agentData.abilities returns undefined (remember that you have an empty object that is asynchronously populated), but you're trying to access it in your template as if an array is present.
You can solve this easily if you conditionally render those <img> elements when agentData.abilities is not undefined, i.e.:
return(
<div className='AgentCard'>
<h2>{agentData['displayName']}</h2>
<img src={agentData['displayIcon']}></img>
<div className='AgentCardBody'>
{agentData.abilities && (
<div className='AbilitiesBar'>
<img src={agentData.abilities[0].displayIcon} className='AbilitiesIcon' />
<img src={agentData.abilities[1].displayIcon} className='AbilitiesIcon' />
<img src={agentData.abilities[2].displayIcon} className='AbilitiesIcon' />
<img src={agentData.abilities[3].displayIcon} className='AbilitiesIcon' />
</div>
)}
</div>
</div>
)
Even better: you can simply iterate through the first 4 entries in agentData.abilities to keep your DOM a bit simpler:
return(
<div className='AgentCard'>
<h2>{agentData['displayName']}</h2>
<img src={agentData['displayIcon']}></img>
<div className='AgentCardBody'>
<div className='AbilitiesBar'>
{agentData.abilities && agentData.abilities.slice(0,4).forEach(ability => (
<img src={ability.displayIcon} className='AbilitiesIcon' />
)}
</div>
</div>
</div>
)

How to display base64 image in AngularJS

Need help again ;)
I would like to show a photo in my Angular page. These are my steps,
REST API gets a document/record from backend MongoDB. The base64 images are stored as this.
The images/data are loaded into an array {{file_src[i]}} in the component code, then the component HTML will show the image as below
Situations:
If I used "img srcs={{file_src[i]}}", I got insecure operation. My REST API server has CORS enabled. Since the image is base64 data and doesn't have any URL, I don't know it is related to CORS.
I googled around and found the ng-src and data-ng-src directives. Both of them don't work too. Please see my binding error below.
Question: how to show the base64 image in my Angular page?
------Code as requested by Vic--------
<section class="fhirForm">
<fieldset>
<legend class="hd">
<span class="text">Photo</span>
</legend>
<div class="bd" formArrayName="photos">
<div *ngFor="let photo of patFormGroup.controls.photos.controls; let i=index" class="panel panel-default">
<div class="panel-body" [formGroupName]="i">
<label>Description</label>
<input type="text" class="form-control" formControlName="desc">
<label>Photo</label>
<input type="file" size="30" multiple formControlName="photo" name="crud8" (change)="photoChange(input, i)" #input>
<!-- img src={{file_srcs[i]}} crossorigin="anonymous" alt="" /-->
<img data-ng-src={{file_srcs[i]}} alt="" />
<span class="glyphicon glyphicon-remove pull-right" *ngIf="patFormGroup.controls.photos.controls.length > 1" (click)="removePhoto(i)"></span>
</div>
</div>
</div>
</fieldset>
<div class="margin-20">
<a (click)="addPhoto()" style="cursor: default">
<small>Add another photo +</small>
</a>
</div>
</section>
initPhoto(desc?: String, photo?: string) {
//Add new entry on the 1 dimensional array. Allow 1 photo per section
this.file_srcs.push(photo);
console.log("Photo for file_srcs: [" + this.file_srcs[this.file_srcs.length - 1] + "]");
return this.formBuilder.group({
desc: [desc],
photo: [photo]
});
}
Please see the console.log. It showed that this.file_srcs are valid.
------------- Error Message in Chrome -------
------------- UPDATE 1 -----------
If I commented out the "input type=file ..." line above the "img src" as below, I can see the photo. What's wrong with my input? Sorry, I don't remember what is that #input for.
Hence, my issue may not be in the photo, but on the input line ;) Shame on me!!!
<label>Photo</label>
<!-- input type="file" size="30" formControlName="photo" name="crud8" (change)="photoChange(input, i)" #input -->
<img src={{file_srcs[i]}} crossorigin="anonymous" alt="" />
--------- RESOLVED -----------
Thanks a lot for all the help!!!
i. the base64 image isn't the root cause;
ii. the file input "input type=file" was initialized by incorrect supplying the base64 image as the default value. It caused the error - failed to set the value of HtmlInputElement is correct in IE. The error message 'Insecure Operation' may be misleading in Firefox.
Hence, the root cause is not related to the base64 image. I would like to delete this thread a week later.
initPhoto(desc?: String, photo?: string) {
this.file_srcs.push(photo);
console.log("Photo for file_srcs[" + (this.file_srcs.length - 1) + "]: [" + this.file_srcs[this.file_srcs.length - 1] + "]");
return this.formBuilder.group({
desc: [desc],
photo: [""] //This was photo: [photo]. After supplying the default value as "", it works well.
});
Best regards,
Autorun
Fetch the base64 content in your controller like this:
$http.get($scope.user.photo).then(function(response) {
$scope.user.data = response.data;
});
then display it on view
<img data-ng-src="data:image/png;base64,{{user.data}}"/>
I use base64 image a lot and haven't see that error before. Is it caused by the crossorigin attribute?
angular.module('test', []).controller('Test', Test);
function Test($scope) {
$scope.base64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAOCAYAAADwikbvAAAA+0lEQVQ4T6WS3W3CMBSFz40QvDJCu0GYALJB2QBeUFzjCm9AJ0gLMQl9STegG5QNYARG6CsI+SKjpmppSY3w8/10fnwIVzy6lE2SollrbBcAPV8ET2fzOzAXDNYPUrx6wxOT9QjkwL4DnWMvODV5wUAP4EclxbiM+i88meUJMUYA3pSMu987qoRLqwDW+10j0rr/4QV/lrNwxwGClpSD9enPHJXTdD5i4vY+YK2F2BjzElrYdwDN05x/KpelMOGJGB0AIQGboYxvz23hR+apyVcO+jq2HCklll7wcT31rbMbgrBU93FUtcBfbSdZdlOztILlbpWq90jOqR8Au8VfIQFLZecAAAAASUVORK5CYII=";
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app='test' ng-controller='Test'>
<img src={{base64}} />
</div>

Call a function in <img> to define the path of the src

I'm trying to to something like that :
<img id="icon" class="cercle icon" src="getIcon({{item.status}})" alt="">
The function is :
getIcon(status){
switch (status) {
case 'Ongoing':
return '../../../../assets/img/icon/PinPlot.png';
case 'Signaled':
return '../../../../assets/img/icon/PinWarning.png';
case 'Finished':
default:
return '../../../../assets/img/icon/Pin red.png';
}
}
But all I get is no image like if it's not found. But no error nor warning.
Any idea ?
Use [src]:
<img id="icon" class="cercle icon" [src]="getIcon(item.status)" alt="">
And also you dont need to getIcon({{item.status}}) but without {{}}.
Although the previous answer of using [src] is the way I would recommend, the reason why your existing technique doesn't work is because you're not using interpolation (i.e. {{....}} ) correctly.
You have:
<img id="icon" class="cercle icon" src="getIcon({{item.status}})" alt="">
when you probably meant:
<img id="icon" class="cercle icon" src="{{ getIcon(item.status) }}" alt="">
Explanation:
You can think of it this way. Within your template, everything outside {{ }} is treated as literal strings. It's only things within the double braces that are treated as code to execute. So, with your example, because of where you put your braces, you'd end up with the string:
src="getIcon(Ongoing)"
after the interpolation, cuz you're only including the item.status within your braces, instead of the entire expression.

ng-if and ng-show in my Ionic application, neither works

The html code goes something like this:
<div ng-if="name=='John'">
<div class="item item-avatar"> <img ng-src="john.jpg"></div>
</div>
<div ng-if="name=='Margaret'"
<div class="item item-avatar"> <img ng-src="margaret.jpg"></div>
</div>
Instead of ng-if, I've tried using ng-show as well. Neither worked. Both John as well as Margaret showed on the page no matter which I used. I tried with ng-switch also.
The variable 'name' I initialized earlier on the same HTML file as:
<a class="item item-avatar item-icon-right" ng-init="name = 'John'" href = "#/Page3"></a>
Clicking on the above line leads to Page3 where I need to display either John or Margaret depending on the value of 'name'.
Is the syntax wrong or something, because that could be very well possible. I'm new to Ionic and AngularJS.
Try this:
<div ng-show="name=='John'" ng-init="name = 'John'">
<div class="item item-avatar"> John</div>
</div>
<div ng-show="name=='Margaret'"
<div class="item item-avatar"> Margaret</div>
</div>
Works for me. I just change ng-if to ng-show - which will shows div content when true and hide it otherwise. I also use ng-init inside a div.
Are you sure you started Angular? Did you set the ng-app directive?
It would help if you could provide a working example if you have other problems.
angular.module('app', []);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-init="name = 'John'">
<button type="button" ng-click="name='John'">John</button>
<button type="button" ng-click="name='Margaret'">Margaret</button>
<div ng-if="name=='John'">
This is John
</div>
<div ng-if="name=='Margaret'">
This is Margaret
</div>
</div>
I fixed you plunker - now it should be working.
Bug #1: ng-init is for initialization not to set values at runtime -> use ng-click instead
Bug #2: You use the same controller for all pages but for each page a new controller will be initialized, which resets the 'name' property
I implemented a setName function to set the name in the rootscope and to go to page3. In a correct implementation you should pass the name as a $stateparam to the new state/page. But for that please have a look at the ui-router documentation.
$scope.setName = function(name) {
console.log(name);
$rootScope.name = name;
$state.go('Page3');
};

HtmlUnit - Unable to get anchors from div

The divs of the HTML page I am targeting look like this:
<div class="white-row1">
<div class="results">
<div class="profile">
<a href="hrefThatIWant.com" class>
<img src = "http://imgsource.jpg" border="0" width="150" height="150 alt>
</a>
</div>
</div>
</div>
<div class="white-row2">
// same content as the div above
</div>
I want to scrap collect the href in each div in a list.
This is my current code:
List<HtmlAnchor> profileDivLinks = (List)htmlPage.getByXPath("//div[#class='profile']//#href");
for(HtmlAnchor link:profileDivLinks)
{
System.out.println(link.getHrefAttribute());
}
This is the error I am receiving (which goes on first line of the for statement):
Exception in thread "main" java.lang.ClassCastException: com.gargoylesoftware.htmlunit.html.DomAttr cannot be cast to com.gargoylesoftware.htmlunit.html.HtmlAnchor
What do you think the issue is?
The issue is you're getting an attribute and then you're casting that attribute to an anchor. I guess the solution with the minimal change to your code would be just modifying the XPath to return an anchor:
htmlPage.getByXPath("//div[#class='profile']//a");
try
//div[#class='profile']//data(#href)