Angular 4 refresh <img src={{ ... }} > when the value changes - javascript

I am using Angular 4 and I have a component where I want to change my user current photo.. so the html code that displays the current user photo is this..
<div class="profilphoto">
<img src= {{currentphoto}}>
</div>
currentphoto contains the current user photo url and I get it from firebase..
After that I display a Gallery of photos so the user can select one and change his profil photo using a form.. the submit code is the following and works fine
onSubmit = function(form) {
this.photoUrl = form.photoUrl;
firebase.database().ref("users/"+this.authService.cusername+"/photo").update({
url: form.photoUrl
}).then(()=>{
this.currentphoto = this.authService.photourl;
console.log("currentphoto:"+this.currentphoto);
}
);
}
Everything works fine except that despite the currentphoto value has changed and database url upadated the html still displays the previous user's image and its annoying(if I refresh the page it shows the new profil image).. Is there any way I can make
<div class="profilphoto">
<img src= {{currentphoto}}>
</div>
detect when currentphoto changes value and Display the image with the new src value??

Try calling the changedetection manually,
constructor(private cdRef: ChangeDetectorRef){
}
Once you set the image
this.currentphoto = this.authService.photourl;
this.cdRef.detectChanges();

This is probably not relevant anymore but in case it could help people get this solved faster, here it is.
If you want to update the image after it has changed write your src like this:
src='{{currentphoto}}?d={{clock_tick}}'
Initialize your clock tick when you first load your component (I use Date.now()) and again after you update the image. This will tell your browser that you updated the image and it will reload it for you.
It worked for me.

Without the entire code of your component/service is hard to know what is the problem, but the best shot is in this line:
onSubmit = function(form) {
probably it's a problem with the 'this' value.
Insert a console.log(this) below this line (inside the function) and check if 'this' is a reference to the component instance or to the window.
Try to use arrow function:
onSubmit = form => {
//do what you need here, call the service, etc...
//and then set the this.currentphoto
}

Have you tried this:
<div class="profilphoto">
<img [src]="currentphoto" >
</div>

Related

Image loading issue with vue

This issue might not be specific to vue but here goes...
I'm searching for some items and retrieving them from a database, each item has a unique name which I use to load their image from an external site, for example:
<img :src="'https://external-site.com/photos/' + item.name + '.jpg'" />
Whenever I search for the first item it returns the item with it's image and details. But whenever I search for a second item, it returns the right details but uses the cached image of the last item until it's own image has loaded.
I decided I would use some events on the image to show a loader before they start loading but I only found that there were three events specific to images: onabort, onerror, onload.
But I need an event to show a loader at the start of downloading the image. If not, is there another way I can resolve this issue?
A common trick to defeating the cache is to add an innocuous, changing parameter to your url, such as a timestamp:
<img :src="'https://external-site.com/photos/' + item.name + '.jpg?x=' + Date.now()" />
The parameter shouldn't interfere with accessing the image, but the browser won't assume the url is the same.
I solved the issue by using Progressive image rendering with vue:
First I installed a package that gave me a v-lazy-image component by npm i v-lazy-image
then I imported the component
<script>
import VLazyImage from "v-lazy-image";
export default {
components: {
VLazyImage
}
};
</script>
The component then allows you to specify the image and a placeholder image to use while the image loads:
<v-lazy-image
:src="'https://external-site.com/photos/' + item.name + '.jpg'"
src-placeholder="/images/default.jpg"
/>
You can see more details of this component here
I had exactly the same issue. And none of the previous answers solved my problem.
At the method that change your items details and images link (ex.: changeDetails()), make a backup of your real image path (impath) at (impath_b) and set your image path to null. Vue.js will draw a transparent image, and after 100ms the real image path (impath) is restored.
changeDetails() {
// for ...
item.impath_b = item.impath; // it's not necessary declare impath_b before.
item.impath = null;
// ...
// just before the method ends:
setTimeout(function () {
vm.revertImages();
}, 100);
},
revertImages() {
// for ...
item.impath = item.impath_b;
item.impath_b = null;
}
At the html code show the image just when it is not null:
<img v-if="item.file!=null" :src="item.file"/>
<img v-else :src="transpGif"/>
Define transpGif at your variables area:
transpGif: 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
more details about this transpGif here .
The idea is to clean and redraw the images with an empty image, and then the new image will be drawn when it be loaded.

How to refresh DOM after changing data attribute

I'm coding little CMS for translations of static pages to many languages. It dynamically refreshes and loads translations etc, but I've got a few bugs which I cannot fix. One of them is when you try to preview page of id 1, but before you were editing page of id 2, it always redirects you to preview of page of id 2.
That's my button in template:
<div class="edit-template-container">
//other code
<button id="a-preview" href="#" class="btn btn-block" target='_blank'>
Preview template
</button>
</div>
And it's function to load preview in new window:
$('#a-preview').on('click', function () {
var pageId = $('#language-choice-select').data('page-id');
console.log(pageId);
window.open('/main/staticPages&staticPageId=' + pageId, '_blank');
});
Then I've read some articles about event-delegation and assumed it could be my problem so changed that code to:
$('.edit-template-container').on('click', '#a-preview', function () {
var pageId = $('#language-choice-select').data('page-id');
console.log(pageId);
window.open('/main/staticPages&staticPageId=' + pageId, '_blank');
});
But it stills redirects to page of id 2 if it was edited before. In DevTools Elements I can see that data-page-id is changed, but console.log always prints for example id: "2" if it was edited before.
Data 'page-id' attribute is changed when I choose page to edit in table, on function which looks like that:
$('table').on('click', '.edit-table-btn', function () {
var pageId = $(this).data("page-id");
//the rest of code
$('#language-choice-select').attr('data-page-id', pageId);
});
What should I do to change page-id data-attribute dynamically in DOM? What should I know about this, are there any fine articles?
Please refer to this existing post:
jQuery Data vs Attr?
Basically, when you use data() on a node, jQuery sets the value on the node object, not on the DOM element.
So, I suggest you to use attr() both to set and to read the value.

sequence of operations in Angular controller not working in a right way

I have a page where a user enters initial data, after that he clicks Calculate. And on click there should appear a gif-image with a loading spinner while the calculations are being made. As soon as the result is ready, the gif-image should disappear and the result should be displayed on the page. Here's the code I'm using:
$scope.loading=false; //initially the img is invisible
$scope.calc=function(){
$scope.loading=true;//make the img visible
var result=MyService.calc(input_data); //processing data
$scope.result=result;
$scope.loading=false;//hide the img
}
And the HTML image is defined like so:
<div class="span1">
<div ng-if="loading"><img ng-src="img/ajax-loader.gif"></div>
</div>
It's an expected order of things to happen. But in reality it works as follows: after clicking Calculate the image doesn't appear, and after some time during which calculations were made the image is shown and escaped.
The calculations are made in a service.
What's the problem? I already tried to make a $q.defer() in the service which resolves with result. And then in the controller display result inside the promise.then function. But it doesn't work.
Use $timeout for this. The model does not get updated in the middle of execution
JavaScript
$scope.calc=function(){
$scope.loading=true;//make the img visible
$timeout(function(){
var result=MyService.calc(input_data); //processing data
$scope.result=result;
$scope.loading=false;//hide the img
});
}
($timeout must be dependency-injected just like $scope)

galleria - run a JavaScript function everytime picture is changed

I am trying to find in the Galleria JavaScript file a place where I tell it to run a JavaScript function every time the current picture is changed (prev, next, or clicking on a thumbnail)
Does anyone with experience with galleria have any ideas?
http://galleria.io/
When you set up your Gallery bind to the image function and you will receive the event every time the image changes. I use it to load text into another area of my page like so.
Galleria.ready(function() {
this.bind("image", function(e) {
$("#text_div").text(arrayOfText[e.index]);
});
});
To make sure you have things setup correctly use it like this,
Galleria.loadTheme('galleria/themes/kscreates/galleria.classic.js');
Galleria.configure();
Galleria.ready(function() {
this.bind("image", function(e) {
console.log(e.index);
});
});
Galleria.run('#galleria');
and have a look in your Safari console and you will see the index of the currently displayed image.
Hope this helps.

execute code AFTER Recaptcha.reload() is finished

I have a function below which is called to reload a recaptcha image. It works, reloads the image but won't do anything after that. Basically the form is small that has this recaptcha on it so I've shrunk it and allowed for clicking to enlarge and all that. If the person presses "get another captcha" which calls reloadCAP() it checks to see if it has the class of being the larger image. if it does i need it to add that class and css back to the elements AFTER the new image has loaded but I can't seem to get it to work. Any ideas?
function reloadCAP() {
if($("#recaptcha_widget img").hasClass('largecap')) {
Recaptcha.reload();
$("#recaptcha_widget img").addClass('largecap');
$('#recaptcha_image').css('height', '62px');
} else {
Recaptcha.reload();
}
}
here's the html for this:
<div id="recaptcha_widget" class="formRow" style="display:none;">
<span class="f_label">Enter Words Below:</span>
<input type="text" class="setWidth" id="recaptcha_response_field" name="recaptcha_response_field" />
<div class="cantread">
<strong>Can't read this?</strong><br />
Get another CAPTCHA
</div>
<div id="recaptcha_image"></div> <!-- image loaded into this div -->
<div class="clear"></div>
<span class="smalltext">(click to enlarge)</span>
<br clear="all" />
</div>
<script type="text/javascript" src="http://api.recaptcha.net/challenge?k=6LfzMMwSAAAAADV6D04jDE6fKwrJ57dXwOEW-vY3&lang=en"></script>
$("#recaptcha_widget img").one('load',function(){
$("#recaptcha_widget img").addClass('largecap');
$('#recaptcha_image').css('height', '62px');
});
This will put a one time only listener on the load event of the image that you are reloading and then executes the folowing code.
I used .one() instead of .load() here because you don't want to attach a new listener every time you call reloadCAP()
Edit
Ok, so here's what I believe the issue is. When you call Recaptcha.reload() it is removing the <img /> and replacing it with a new one. So when we are trying to attach the event it is getting removed as the image gets removed.
What you need to do is place the class largecap on the recaptcha_image div and modify your css style to look like
.largecap img {
height: whatever;
width: whatever;
}
Not the ideal solution, but you could put the addClass code above Recaptcha.reload() and just delay it by a second or two.
Hope that helps.
It sounds like what you actually need is custom theming such that you can style the captcha/image/etc exactly as needed: https://developers.google.com/recaptcha/docs/customization
If you do want to stick to your current implementation, you can hook into Recaptcha's built in (and undocumented) callback functions prior to calling Recaptcha.create().
//Called after Recaptcha.reload() is finished loading
Recaptcha._alias_finish_reload = Recaptcha.finish_reload;
Recaptcha.finish_reload = function (challenge, b, c) {
//Call original function that creates the new img
Recaptcha._alias_finish_reload(challenge, b, c);
$("#recaptcha_widget img").toggleClass('largecap', true);
}
//Called when the initial challenge is received on page load
Recaptcha._alias_challenge_callback = Recaptcha.challenge_callback;
Recaptcha.challenge_callback= function () {
//Call original function that creates the new img
Recaptcha._alias_challenge_callback();
$("#recaptcha_widget img").toggleClass('largecap', true);
}
The reason you're even having this problem is because Recaptcha destroys and creates a new img everytime it reloads, so the styling you added manually will be lost.

Categories