Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using webshims polyfill in an Angular app

I'm trying to use the webshims polyfill in an angular app, which is also using requirejs for dependency management. I'm trying to shim the absence of the form attribute in form fields like input and button, which tells the browser which form a particular button or input belongs to. IE9 lacks this feature.

I figured that the best way to use this polyfill would be to create a form directive, and invoke the $.webshims.polyfill('forms') inside the link function.

The directive
define(['angular', 'webshims'], function(angular) {
  return angular.module('myApp').directive('form', ['$window', function($window) {
    return {
      restrict: 'E',
      scope: false,
      link: function($scope, iElement, iAttrs) {
        if (!(window.Modernizr.input.placeholder || window.Modernizr.input.autofocus)) {
          $.webshims.setOptions({
            waitReady: false
          });
          $.webshims.polyfill('forms');
        }
      }
    };
  }
]);

Here is how I'm loading the webshims polyfill right now:

My Requirejs config
app: {
  options: {
    baseUrl: 'src/apps',
    stubModules: ['cs'],
    paths: {
      jquery: '../public/components/jquery/jquery',
      ....
      angular: '../public/components/angular/angular',
      ....
      webshims: '../public/components/webshim/src/polyfiller',
    },
    shim: {
      angular: {
        deps: ['jquery'],
        exports: 'angular'
      },
      ...
      priority: ['angular']
    }
  }
}

The thing is that even though the shim loads, and even calls the correct functions, the shims don't seem to be working, as IE9 still has problems with HTML5 Form attributes (placeholder, the form attribute, etc)

What am I missing here?

like image 809
kumarharsh Avatar asked Dec 17 '13 14:12

kumarharsh


2 Answers

Just ran into this issue myself and I think I have a simpler solution which seems to work fine:

Just call the updatePolyFill method from the controller of your main index page after a view loads:

//Polyfill needs update when dynamic view loads
$scope.$on('$viewContentLoaded', function() {
    $('body').updatePolyfill();
});

The trick is that this event bubbles up from the view in the ng-view block so you need to do this in the controller above that view, not in the view's controller. Also, I guess, it should not be called if it's not polyfilling already, not sure how to do that yet though and it didn't appear to conflict at all testing with Chrome which needs no polyfills for what I'm doing (form controls only).

like image 107
JohnC Avatar answered Oct 11 '22 17:10

JohnC


I have no experience with angular, so I don't know wether your descision to do this in a "form" directive is right (But I doubt it).

But first: webshims polyfiller file registers as a named amd module called 'polyfiller'. It would be good to rename your webshims into polyfiller

define(['angular', 'polyfiller'], function(angular)

and:

polyfiller: '../public/components/webshim/src/polyfiller',

inside of your define function you should also set the basePath correctly before you are calling the polyfill method:

webshims.setOptions({
   waitReady: false,
   basePath: '../public/components/webshim/src/shims/'
});

Additionally autofocus and placeholder are supported in IE10, but the form attribute isn't support even in IE11. So you should remove the Modernizr test.

So let's look what your current problem is.

Can you run the following code in IE9's console webshims.isReady('forms')?

If true: If forms is ready, run the follwing code in IE9's console $('body').updatePolyfill(). Does this help?

If false: Run the following code in your IE9's console webshims.modules["form-core"].loaded

Does it return true or undefined/false.

If it returns undefined/false: Make sure that a) webshims.polyfill('forms'); is really called and b) there is no network error -> The file is loaded without 404 also see the basePath config above.


Something about webshims loading and executing:

Normally you should load webshims once on your app initializing. And then everytime your view changes you should invoke the .updatePolyfill on the dom element that was changend.

Some frameworks have special events for this. For example jQuery mobile uses the pageinit event.

In this case (jQM) you would write:

$(document).on('pageinit', function(e){
    $(e.target).updatePolyfill();
});

In some frameworks you need to use a setTimeout:

render: function(target){
    setTimeout(function(){
        $(target).updatePolyfill();
    }, 0);
}
like image 38
alexander farkas Avatar answered Oct 11 '22 18:10

alexander farkas