ng-srcset images initially not displaying in IE11 intermittently - angularjs

The page loads without any of the images displaying on IE11 only, but refreshes them accordingly when we resize the browser intermittently (1/3 loads). We cannot replicate this with any of the other browsers. srcset works fine by itself with static content.
Here is a Plunker example of it not working in IE11.
Or quick and easy, the actual img html we're using:
<img data-ng-srcset="{{::image.url}}, {{::image.url2x}}" alt="{{::image.name}}"/>
The images or surrounding divs do not have any transitions, shadows or opacity applied.
The html renders fine with angular passing over and rewriting the srcset attribute correctly. The images just do not appear, only the alt tag. Wondering if this could be a call stack issue due to the intermittence of it, maybe a race condition with Picturefill loading before angular finishes a digest or something.
Cheers in advance!

A work around if you use PictureFill in a loop and in a specific case (not on all images of your application), is calling a function that launch PictureFill directly from HTML, after last item loaded (this is not the best practice but fix the IE11 problem) :
<picture><!-- Your image --></picture>
<span ng-if="$last">
{{ controllerAlias.launchPictureFill() }}
</span>

Came across this as a solution: http://tech.endeepak.com/blog/2014/05/03/waiting-for-angularjs-digest-cycle/
var waitForRenderAndDoSomething = function() {
if($http.pendingRequests.length > 0) {
$timeout(waitForRenderAndDoSomething); // Wait for all templates to be loaded
} else {
$window.picturefill();
}
}
$timeout(waitForRenderAndDoSomething);
The only issue that the blog post describes is here, so if anyone has anything better please let me know:
The $http.pendingRequests supposed to be used for debugging purpose only. If angular team decides to remove this, you can implement the same using http interceptors as suggested in this link.

Related

OnsenUI loads page in text, via a splitter

I have previously created a web app, and now I would like to integrate it with OnsenUI to enable my app to be used on all mobile devices as well as the web.
I am using a splitter in a toolbar which will be the header of all pages, and it will redirect the user to other pages when they click an item in it. Clicking the home item successfully redirects to the home page (index, which is already loaded correctly). However, clicking any of the other items in the splitter redirects me to the requested page, but shows the content of the file in text format instead of actually rendering the page. It looks like the following, except it's all jumbled together with no spaces:
searchForTrainer.jade:
//-ons-template(id='searchForTrainer.jade')
ons-page(ng-controller='SearchController' ng-init='showme = false; getAllTrainers();')
ons-toolbar
.left
ons-toolbar-button(ng-click='mySplitter.left.open()')
ons-icon(icon='md-menu')
.center
| Search Trainer
// ***** I cut off the rest of the file for simplicity
// ***** I should still be able to see the toolbar if the page loads correctly
Here is the content of index.jade:
doctype html
html
head
link(rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css')
link(rel='stylesheet', href='/stylesheets/style.css')
link(rel='stylesheet' type='text/css' href='/stylesheets/jquery.datetimepicker.css')
link(rel='stylesheet' type='text/css' href='/stylesheets/ratings.css')
link(rel='stylesheet' type='text/css' href='/stylesheets/searchTrainerTab.css')
link(rel='stylesheet' type='text/css' href='/onsenui/css/onsenui.css')
link(rel='stylesheet' type='text/css' href='/onsenui/css/onsen-css-components.css')
block loadfirst
script(src='https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js')
script(src="https://code.jquery.com/jquery-1.12.3.min.js"
integrity="sha256-aaODHAgvwQW1bFOGXMeX+pC4PZIPsvn2h1sArYOhgXQ=" crossorigin="anonymous")
script(src='/onsenui/js/onsenui.js')
script(src='/onsenui/js/angular-onsenui.js')
script(src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js')
script(src='/angular/fitnessapp.js')
script(data-require='angular-credit-cards#*', data-semver='3.0.1', src='https://rawgit.com/bendrucker/angular-credit-cards/v3.0.1/release/angular-credit-cards.js')
script(async='', defer='', src='https://maps.googleapis.com/maps/api/js?key=AIzaSyDcVf7YAPNwa8gUsMCOZNQZA31s5Ojf2n8&libraries=places')
body
ons-splitter(var='mySplitter', ng-controller='RootController as splitter')
ons-splitter-side(side='left', width='220px', collapse='', swipeable='')
ons-page
ons-list
ons-list-item(ng-click="splitter.load('index.jade')", tappable='')
| Home
ons-list-item(ng-click="splitter.load('searchForTrainer.jade')", tappable='')
| Search Trainer
ons-list-item(ng-click="splitter.load('searchForEvent.jade')", tappable='')
| Search Event
ons-list-item(ng-click="splitter.load('trainerAddEvent.jade')", tappable='')
| Create Event
ons-list-item(ng-click="splitter.load('userProfile.jade')", tappable='')
| Profile
ons-list-item(ng-click="splitter.load('addPayment.jade')", tappable='')
| Payment
ons-list-item(ng-click="splitter.load('userSettings.jade')", tappable='')
| Settings
ons-list-item(ng-click="splitter.load('trainerSignup.jade')", tappable='')
| Trainer Application
ons-list-item(ng-click="href='/logout'", tappable='')
| Logout
ons-splitter-content(page='index.jade')
ons-template(id='index.jade')
ons-page(ng-controller='MapController' ng-init='getEvents()')
ons-toolbar
.left
ons-toolbar-button(ng-click='mySplitter.left.open()')
ons-icon(icon='md-menu')
.center
| Fitness App
//-.right
a(href='https://www.paypal.com/webapps/mpp/paypal-popup', title='How PayPal Works', onclick="javascript:window.open('https://www.paypal.com/webapps/mpp/paypal-popup','WIPaypal','toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=1060, height=700'); return false;")
img(src='https://www.paypalobjects.com/webstatic/mktg/logo/bdg_now_accepting_pp_2line_w.png', border='0', alt='Now Accepting PayPal')
//- google maps stuff
ons-input#pac-input.controls(type='text', placeholder='Search Box')
div#map.col-md-12
ons-bottom-toolbar
.center
| Fitness App
block scripts
script.
// ***** I cut out javascript related to Google Maps for simplicity
here is the splitter load page function I am using in my angular file:
this.load = function(page) { console.log("The page is: " + page);
mySplitter.content.load(page)
.then(function() {
mySplitter.left.close();
});
};
Has anyone successfully built an Onsen app using Jade?
UPDATE
When I leave the code in html instead of jade, everything works correctly. When I convert it back to jade it shows up as text again.
UPDATE 2
Using Solution 1 from the selected answer, I realized and solved my problem with the guidance from the selected answer on my other post:
Answer
By the looks of it you seem to be using Jade on the server side.
To solve the problem I see a couple possible solutions.
Solution 1:
Make sure that whatever Onsen UI is receiving is pure HTML. You're free to use Jade, but as it stands Onsen does not have Jade bundled inside, so there is no way for it to support it out of the box. However as long as Onsen sees only html it should be fine.
The reason why the ons-template(id='index.jade') works initially is actually because when you serve the page you are actually serving actual html, so when onsen starts the contents of that template are actually pure html.
In searchForTrainer.jade it seems that you are giving it raw jade, which it does not know how to handle. You can handle this on the server side, making sure that the request for the searchForTrainer returns html. Returning jade.renderFile('searchForTrainer.jade') from the server instead of the jade file itself should solve the issue.
Solution 2:
As you noticed as long the contents are inside the initial page everything will be fine. So you could just put all your ons-templates inside the initial page.
If you want to retain your current file structure you can just do
include searchForTrainer.jade
while having an ons-template tag in the file itself. That way in the end the result will be a page with the template already converted into html.
Solution 3:
The final option is to give the raw jade files, but help Onsen understand Jade, so that it can use them properly. To do that you need to include jade.js and modify Onsen UI so that it uses it.
However since Onsen does not currently provide an official API for switching template engines whatever hack we use now might break in the future. It's possible that in the near future a feature like that may be implemented, but in order to do it now we need to wrap some of onsen's internal functions.
Here's a simple example to do it.
module.run(function($onsen) {
var old = $onsen.normalizePageHTML;
ons._internal.normalizePageHTML = $onsen.normalizePageHTML = function(html) {
return old(jade.render(html, {}));
};
});
And here's also a working Demo showing this solution in action.
Note: that demo actually checks for a comment // jade at the beginning just to be safe.
Which solution to choose?
Solution 1 - I think this makes most sense as it retains a clear separation of concerns. If you want to change the templating engine it should be handled only in one place. Onsen does not need to know what you're using on the server as long as it gets what it wants.
Solution 2 - Not the best way to solve the problem, but it may be the easiest to use if you just want things to work. One minus is that with it you would load all the templates at the beginning, which may not be very good.
Solution 3 - While this solution can work I would suggest avoiding it as handling jade on the frontend would result in poor performance. It's could be an option if you actually decide not to rely on the server.

Safari breaks when using exclamation mark in Angular condition

This sounds wacky but we're currently consistently able to reproduce this issue, and I wanted to know if anyone has seen anything like it, or knows what could be causing it.
We have an Angular 1.4.1 application, and in some of our html partials we have conditions in the following form:
<div ng-if="!obj.myvar">
... contents ...
</div>
Where in your JS you've set up your scope accordingly:
$scope.obj = { myvar: false }
This works as expected in all browsers, except iOS Safari (we've seen this on iPhone and iPad):
On the initial load, all elements following the ng-if fail to load
If you manually refresh the page, it will then work as expected
We've found that changing the syntax to this fixes the issue:
<div ng-if="obj.myvar === false">
... contents ...
</div>
But I'm not hugely satisfied with that as a solution, and it doesn't explain why this issue is happening at all.
Word of warning if you're trying to replicate this - this isn't reproducible on jsFiddle. I assume that's because the results window isn't a "true" browser.

Loader/spinner animantion while route is changing

How can I show a spinner or loader gif animation while route is changing from one to another.
I am using ng view like as follows:
<div ng-view class="view-animate">
</div>
I am loading templates from server and also inline. While the HTTP request is pending I need to show the spinner/loader... any snippets?
You can show and hide the loader when location change starts and is completed, respectively.
Here is a plunkr that I have created for this situation. This uses ui-router and is taken from one of the apps that I have created, so it may not be useful as-is, but it will give you an idea on how to approach the problem.
HTML Code inserted below just to keep SO happy...
<ui-view class="view"></ui-view>
<div loader="" class="ng-hide"></div>
I hope it helps.
Abhi.

Google translate widget appears twice

I have a responsive site that uses the google translate widget. The weird thing is that for some time the widget now appears twice, and this seem to be related to the responsive design because if I place the same widget code on a simple html page it only appears once. I have no idea on how to solve this. Has anyone come across this?
Update.
I have discovered that this is caused by jquery.themepunch.showbizpro.min.js, if I remove that one the widget only appears once. I have not found a way to fix this yet but there might be a way. I found this piece of code.
<script>
function googleTranslateElementInit() {
new google.translate.TranslateElement(
{ pageLanguage: 'sv' },
'google_translate_element'
);
/*
To remove the "powered by google",
uncomment one of the following code blocks.
NB: This breaks Google's Attribution Requirements:
https://developers.google.com/translate/v2/attribution#attribution-and-logos
*/
// Native (but only works in browsers that support query selector)
if(typeof(document.querySelector) == 'function') {
document.querySelector('.goog-logo-link').setAttribute('style', 'display: none');
document.querySelector('.goog-te-gadget').setAttribute('style', 'font-size: 0');
}
//If you have jQuery - works cross-browser - uncomment this
jQuery('.goog-logo-link').css('display', 'none');
jQuery('.goog-te-gadget').css('font-size', '0');
}
</script>
This code remove the logo, so I'm thinking that if I use javascript I could check and remove duplicate occurrences of <select class="goog-te-combo"> then I would only have one left, is that possible?
This happened to me using Bootstrap. I had two instances of the Google Translate code - one instance for larger screen sizes and another that was only visible for smaller screens. Both showed up regardless of screen size. Bootstrap classes like visible-xs and hidden-xs do not seem to affect the display of the Google Translate button.
You can set a global counter and make sure it's only called once.
<div id="google_translate_element"></div>
<script type="text/javascript">
var duplicate_google_translate_counter = 0;//this stops google adding button multiple times
function googleTranslateElementInit() {
if (duplicate_google_translate_counter == 0) {
new google.translate.TranslateElement({pageLanguage: 'en'}, 'google_translate_element');
}
duplicate_google_translate_counter++;
}
</script>
<script type="text/javascript" src="https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
Had the same problem on RoR. Problem caused by cashing pages with turbolinks. I solved it with deprecating cashing all links in (when script loading it adds attr "data-turbolinks="false" to the body-tag)
Hello to all! I had the same issue and I KNOW is not the best practice but I fixed it with CSS just adding overflow: hidden and a right border on it.
It visually fix the problem until we get a solution and really saved time diving into JS files. Hope it works for you too. Cheers!

Image not showing in angularjs, mobile

Image not showing in ng-repeat, getting all data from indexeddb and binding to page everything show up expect img in blackberry 10 webworks
<img data-ng-src='{{item.Picture}}' width="100px;" height="100px;"/>
{
id:48758,
Botanical_name:"Cladothamnus pyroliflorus",
Common_name:"Himalayan Cotoneaster ",
Picture: "images/Fplants/Cladothamnus pyroliflorus.png",
},...
This wouldn't seem like an issue with IndexedDB.
For non-Angular directive attributes, such as src you want to interpolate as in the code below:
<img src='{{item.Picture}}' width="100px;" height="100px;"/>
For Angular directive attributes, there's no need for such interpolation:
<img data-ng-src='item.Picture' width="100px;" height="100px;"/>
As your data is going to be undefined on bootstrap, you want to use the latter approach. It prevents the browser from trying to load undefined as an image source.
Also, please note vaibhav's comment above. Without a leading slash, you'll load the images directory as relative to the current. While that may be what you're going for, it's probably going to make your code more reusable to include the leading slash regardless.
Update: If you're in an ng-repeat, note that your scope is not the scope in which the ng-repeat directive appears but it's own, brand new scope. Perhaps try out $parent.item.Picture
I'm having the same problem, it occurs with the image filename having spaces in between , maybe we could write a directive the removes the space from the filename as I'm calling the image via other variable such as title..
app.config(['$routeProvider','$compileProvider',function($routeProvider, $compileProvider){ $compileProvider.imgSrcSanitizationWhitelist('img/');

Resources