Injecting angular directive through mapquest library. Directive not detected - angularjs

I have a directive, <flightpoint></flightpoint>.
I need to add this directive to Mapquest's map via map.addShape().
However, angular is not aware of the new directive on the map, therefore it doesn't process it (its blank html).
MQA.withModule('htmlpoi', function() {
var poi=new MQA.HtmlPoi( {lat:39.743943, lng:-105.020089} );
poi.setHtml("<flightpoint></flightpoint>", -6, -20, 'mqa_nostyle_htmlpoi');
var x = routeMap.addShape(poi);
});
A few things I've tried.....
1. $compile
MQA.withModule('htmlpoi', function() {
var poi=new MQA.HtmlPoi( {lat:39.743943, lng:-105.020089} );
poi.setHtml($compile("<flightpoint></flightpoint>")($scope), -6, -20, 'mqa_nostyle_htmlpoi');
var x = routeMap.addShape(poi);
$scope.$apply();
});
Result: [object Object] is displayed on the map instead of my directive.
2. angular.bootstrap()
MQA.withModule('htmlpoi', function() {
var poi=new MQA.HtmlPoi( {lat:39.743943, lng:-105.020089} );
poi.setHtml("<flightpoint></flightpoint>", -6, -20, 'mqa_nostyle_htmlpoi');
var x = routeMap.addShape(poi);
angular.bootstrap(document, ['app']);
});
Result: "Error: App Already Bootstrapped with this Element 'document'"
If I was able to compile it after its been added that would be okay too.

This is a little sloppy but its working for me.
I'm able to add a dummy tag and insert compiled angular into it.
MQA.withModule('htmlpoi', function() {
var poi=new MQA.HtmlPoi( {lat:39.743943, lng:-105.020089} );
poi.setHtml("<span id=\"insertDirectiveHere\"></span>", -6, -20, 'mqa_nostyle_htmlpoi');
routeMap.addShape(poi);
// now that you've added the span we can insert compiled angular on that tag
var domElem = document.getElementById('insertDirectiveHere');
domElem.innerHTML = "<flightpoint></flightpoint>";
$compile(domElem)($scope);
});

Related

Print Angular processed HTML

I'm trying to print a div that has been rendered using Angular. I'm using this answer as a starting point https://stackoverflow.com/a/30765875/285190, with the print function being pretty simple
$scope.printIt = function(){
var table = document.getElementById('printArea').innerHTML;
var myWindow = $window.open('', '', 'width=800, height=600');
myWindow.document.write(table);
myWindow.print();
};
The problem is the innerHTML contains all the items that would exist if the ng-show ng-hide directives hadn't been executed.
Is there a way to get the actual HTML the client is seeing, i.e. after Angular has performed its magic?
Please use $compile service to transform angularized HTML to actual HTML.
Demonstration of $compile
https://stackoverflow.com/a/26660649/5317329
$scope.printIt = function () {
angular.element('#tempHtml').html("");
var table = document.getElementById('printArea').html();
var compiledHTML = $compile(table)($scope);
$timeout(function () {
angular.element(document.querySelector('#tempHtml')).append(compiledHTML);//Please added <div id="tempHtml"></div> in page/View for temporary storage, Clear the div after print.
console.log(angular.element('#tempHtml').html());
var myWindow = $window.open('', '', 'width=800, height=600');
myWindow.document.write(angular.element('#tempHtml').html());
myWindow.print();
angular.element('#tempHtml').html("");//Clearing the html
}, 300); // wait for a short while,Until all scope data is loaded If any complex one
};
Hope this will help you

using leaflet-popup-angular with ionic application

I am using this library for my ionic app. When I use leaflet-popup-angular with ionic,when I click the circle the popup doesn't work.and gives me this error Uncaught TypeError: Cannot read property 'get' of undefined.This errors sign this line inside the L.Popup.Angular.js library file.->>
var $rootScope = $injector.get('$rootScope'),
$compile = $injector.get('$compile'),
$controller = $injector.get('$controller');
.controller('MapCtrl', function ($scope) {
var map = L.map('map', { zoomControl: false });
var noControllerPopup = L.popup.angular({
template: `Hello world`,
}).setContent('But we can still use templates and $content.');
L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(map).bindPopup(noControllerPopup);
//my Tile...
});
can u please help me to solve this problem...
Update to version 1.0.1. Just released on bower and npm. The older versions assumed that you had your ng-app on the root html tag. This one looks for ng-app directly.

AngularJS + Jade ng-repeat does not fill the table

I am trying to fill a table via AngularJS.
My controller receives through a socket data.
The data looks like:
[{score: 2, team: 1, kills: 9, assists: 2, deaths: 0}, {score: 2, team: 1, kills: 9, assists: 2, deaths: 0}]
I tried to reduce the code to the relevant stuff, but maybe I did something wrong by that, but the jade templates renderes usually.
index.jade
doctype html
html(lang='en', ng-app="app")
head
meta(charset='utf-8')
meta(http-equiv='X-UA-Compatible', content='IE=edge')
meta(name='viewport', content='width=device-width, initial-scale=1')
title= title
// Bootstrap CSS
link(href='stylesheets/bootstrap.min.css', rel='stylesheet')
// Socket
script(src='https://cdn.socket.io/socket.io-1.3.5.js')
// jQuery
script(src='http://code.jquery.com/jquery-2.1.3.min.js')
// Angular
script(src='https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js')
script(src='javascripts/controller.js')
// Main CSS
link(href='stylesheets/main.css', rel='stylesheet')
body(ng-controller="controller")
.content.row
.col-md-12.data
.table-responsive
table.table.table-hover
thead
tr
th Score
th Kills
th Assists
th Deaths
tbody
tr(ng-repeat="1 in data")
td {{1.score}}
td {{1.kills}}
td {{1.assists}}
td {{1.deaths}}
script(src='javascripts/bootstrap.min.js')
controller.js
var app = angular.module('app', []);
app.controller('controller', function($scope) {
var socket = io('http://localhost:8080');
socket.on('data', function(data) {
$scope.data = data;
});
});
My controller receives the data and when I do console.log($scope.data) it returns me my sent data.
The problems must be somewhere in the jade template.
You need to do $scope.$apply() after assigning data in socket.on('data' event. Because udpating scope variable through an events will not run digest cycle. you need to run it manually by call $apply() on $scope or either you could wrap function inside $scope.$apply(function(){ //do scope variable updation from here })
Code
var app = angular.module('app', []);
app.controller('controller', function($scope) {
var socket = io('http://localhost:8080');
socket.on('data', function(data) {
$scope.data = data;
$scope.$apply();
});
});

Angularjs E2E Testing with Angular-UI Select2 Element

I have a partial with a select2 element utilizing Angular UI http://angular-ui.github.io/
The issue I am running into is that the element is required and although i have successfully set the field through the following code, the required attribute is not removed as Angular's model must not be updating due to the outside change and I am not sure how to either provide a $scope.apply() or utilize another function of Angular to continue the test.
First to allow for direct jQuery functions to run: (taken from How to execute jQuery from Angular e2e test scope?)
angular.scenario.dsl('jQueryFunction', function() {
return function(selector, functionName /*, args */) {
var args = Array.prototype.slice.call(arguments, 2);
return this.addFutureAction(functionName, function($window, $document, done) {
var $ = $window.$; // jQuery inside the iframe
var elem = $(selector);
if (!elem.length) {
return done('Selector ' + selector + ' did not match any elements.');
}
done(null, elem[functionName].apply(elem, args));
});
};
});
Then to change the field value:
jQueryFunction('#s2id_autogen1', 'select2', 'open');
jQueryFunction('#s2id_autogen1', 'select2', "val", "US");
jQueryFunction('#s2id_autogen1', 'select2', 'data', {id: "US", text: "United States"});
jQueryFunction('.select2-results li:eq(3)', 'click');
jQueryFunction('#s2id_autogen1', 'trigger', 'change');
jQueryFunction('#s2id_autogen1', 'select2', 'close');
input('request._countrySelection').enter('US');
Note that not all of those functions are needed to reflect the changes to the ui, merely all that I have utilized to try and get this working...
To get this to work I consulted both Brian's answer and sinelaw, but it still failed in my case for two reasons:
clicking on 'div#s2id_autogen1' does not open the select2 input for me, the selector I used was 'div#s2id_autogen1 a'
getting the select2 element I would get the ElementNotVisibleError, probably because my select2 is inside a bootstrap modal, so I explicitly wait for the element to be visible before clicking it (you can read the original hint I read to use this here).
The resulting code is:
function select2ClickFirstItem(select2Id) {
var select2Input;
// Wait for select2 element to be visible
browser.driver.wait(function() {
select2Input = element(by.css('#s2id_' + select2Id + ' a'));
return select2Input;
}).then(function() {
select2Input.click();
var items = element.all(by.css('.select2-results-dept-0'));
browser.driver.wait(function () {
return items.count().then(function (count) {
return 0 < count;
});
});
items.get(0).click();
});
}
Hope it helps.
I was unable to get this to work within the Karma test runner, however this became significantly easier within the protractor test suite.
To accomplish this within the protractor test suite I used the following to select the first select2 box on the page and select the first option within that box:
var select2 = element(by.css('div#s2id_autogen1'));
select2.click();
var lis = element.all(by.css('li.select2-results-dept-0'));
lis.then(function(li) {
li[0].click();
});
The next select2 on the page has an id of s2id_autogen3
I'll second what #Brian said if you use protractor and the new karma this has worked for me:
function uiSelect(model, hasText) {
var selector = element(by.model('query.cohort')),
toggle = selector.element(by.css('.ui-select-toggle'));
toggle.click();
browser.driver.wait(function(){
return selector.all(by.css('.ui-select-choices-row')).count().then(function(count){
return count > 0;
});
}, 2000);
var choice = selector.element(by.cssContainingText('.ui-select-choices-row',hasText));
choice.click();
};
use it like:
if the value of the item you want to select is "Q3 2013" you can provide it the model of the selector and an exact or partial text match of the item you want to select.
uiSelect('query.cohort','Q3 2013');
or
uiSelect('query.cohort','Q3');
will both work
I made it work under Karma with following changes.
Add following DSL to the top of your e2e test file:
angular.scenario.dsl('jQueryFunction', function() {
return function(selector, functionName /*, args */) {
var args = Array.prototype.slice.call(arguments, 2);
return this.addFutureAction(functionName, function($window, $document, done) {
var $ = $window.$; // jQuery inside the iframe
var elem = $(selector);
if (!elem.length) {
return done('Selector ' + selector + ' did not match any elements.');
}
done(null, elem[functionName].apply(elem, args));
});
};
});
Then to change select2 value in your scenario use
it('should narrow down organizations by likeness of name entered', function() {
jQueryFunction('#s2id_physicianOrganization', 'select2', 'open');
jQueryFunction('#s2id_physicianOrganization', 'select2', 'search', 'usa');
expect(element('div.select2-result-label').count()).toBe(2);
});
Sometimes the select2 may take time to load, especially when working with ajax-loaded data. So when using protractor, and expanding on Brian's answer, here's a method I've found to be reliable:
function select2ClickFirstItem(select2Id) {
var select2 = element(by.css('div#s2id_' + select2Id));
select2.click();
var items = element.all(by.css('.select2-results-dept-0'));
browser.driver.wait(function () {
return items.count().then(function (count) {
return 0 < count;
})
});
items.get(0).click();
}
This uses the fact that driver.wait can take a promise as a result.

Twitter typeahead.js: Possible to use Angular JS as template engine? If not how do I replace "{{}}" for Hogan/Mustache js?

I am working with twitter's typeahead.js and I was wondering if it was possible to modify hogan.js to use something other than {{}}?
I am looking at the minified code now and I have no idea what to change for something so simple. Doing a find and replace breaks it.
I am asking this mainly because I'm using Angular JS but twitter's typeahead requires a templating engine, causing hogan and angular's {{}} to clash. An even better solution would be simply modifying Angular JS (I know it's not a templating engine) and ditching Hogan to fit the following criteria:
Any template engine will work with typeahead.js as long as it adheres to the following API:
// engine has a compile function that returns a compiled template
var compiledTemplate = ENGINE.compile(template);
// compiled template has a render function that returns the rendered template
// render function expects the context to be first argument passed to it
var html = compiledTemplate.render(context);
Ignore the documentation on this, just look at the source code:
function compileTemplate(template, engine, valueKey) {
var renderFn, compiledTemplate;
if (utils.isFunction(template)) {
renderFn = template;
} else if (utils.isString(template)) {
compiledTemplate = engine.compile(template);
renderFn = utils.bind(compiledTemplate.render, compiledTemplate);
} else {
renderFn = function(context) {
return "<p>" + context[valueKey] + "</p>";
};
}
return renderFn;
}
It happens you can just pass a function to template, callable with a context object which contains the data you passed in the datum objects at the time of instantiation, so:
$('#economists').typeahead({
name: 'economists',
local: [{
value: 'mises',
type: 'austrian economist',
name: 'Ludwig von Mises'
}, {
value: 'keynes',
type: 'keynesian economist',
name: 'John Maynard Keynes'
}],
template: function (context) {
return '<div>'+context.name+'<span>'+context.type.toUpperCase()+'</span></div>'
}
})
If you want to use Hogan.js with Angular, you can change the delimiters by doing something like:
var text = "my <%example%> template."
Hogan.compile(text, {delimiters: '<% %>'});
It appears that the template engine result that typeahead.js expects is an html string and not the dom element (in dropdown_view.js). So I am not sure there is a good solution for using an angular template. As a test I was able to get it binding the result to an angular template but it has to render to an element and then get the html value from the element after binding with the data. I don't like this approach but I figured someone might find it useful. I think I will go with a template function like in the previous post.
Jade template looks like
.result
p {{datum.tokens}}
p {{datum.value}}
Directive
angular.module('app').directive('typeahead', [
'$rootScope', '$compile', '$templateCache',
function ($rootScope, $compile, $templateCache) {
// get template from cache or you can load it from the server
var template = $templateCache.get('templates/app/typeahead.html');
var compileFn = $compile(template);
var templateFn = function (datum) {
var newScope = $rootScope.$new();
newScope.datum = datum;
var element = compileFn(newScope);
newScope.$apply();
var html = element.html();
newScope.$destroy();
return html;
};
return {
restrict: 'A',
link: function (scope, element, attrs, ctrl) {
element.typeahead({
name: 'server',
remote: '/api/search?q=%QUERY',
template: templateFn
});
element.on('$destroy', function () {
element.typeahead('destroy');
});
element.on('typeahead:selected', function () {
element.typeahead('setQuery', '');
});
}
};
}
]);

Resources