Angular iframe dynamisch: $sce: Cannot Read property of undefined - angularjs

I try to make a word combinator for keywords. After combining them I want to load dynamically google search requests into an iframe. Unfortunately I have some problems with $sce-service.
Errormessage:
TypeError: Cannot read property 'trustAsUrl' of undefined
Same error for $sce.trustAsResourceUrl(...);
My plunkr:
http://plnkr.co/edit/N2nzBVElPtegaPYUCXlz
Important part:
Controller.js
var keywordAppControllers = angular.module('keywordAppControllers', []);
keywordAppControllers.controller('KeywordCtrl', ['$scope','$sce',
function ($scope) {
$scope.myData = {};
$scope.myData.previewUrl="";
$scope.serpPreview = function(keyword, $sce, $scope) {
previewUrl="https://www.google.de/search?q=" + encodeURIComponent(keyword);
// previewUrl="https://www.google.de/search?q=" + keyword;
console.log(previewUrl);
trustedUrl = $sce.trustAsUrl('https://www.google.de/');
console.log(trustedUrl);
// $scope.myData.previewUrl = $sce.trustAsUrl('www.google.de/');
// $scope.myData.previewUrl = $sce.trustAsUrl('https://www.google.de/');
// $scope.myData.previewUrl = $sce.trustAsUrl('https://google.de/');
// $scope.myData.previewUrl = $sce.trustAsUrl('//google.de/');
};
// create a blank object to hold our form information
// $scope will allow this to pass between controller and view
$scope.formData = {};
}
]);
App.js:
var keywordApp = angular.module('keywordApp', [
'keywordAppControllers'
]).config(function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
// Allow same origin resource loads.
'self',
// Allow loading from our assets domain. Notice the difference between * and **.
'https://google.de/*',
'http://google.de/*',
'https://google.de/**',
'http://google.de/**'
]);
});

Related

Controller not loading value from factory after ui-router state change

I have a list of icons on a webpage generated from an object array. When the user clicks on an icon, the corresponding object from the array is passed to a function in a factory which saves the name of the object selected, then $state.go is called to change routes. On the new route a controller is loaded which loads the same factory and tries to access the name of the saved object. The problem is that about 7 times out of 10, it works perfectly, and the other 3 times is gives a "Unable to get property 'name' of undefined or null reference" type error.
Here is the controller passing the selected value to the factory:
platformHome.controller('PlatformHome', ['$scope', 'appManager', '$state', function ($scope, appManager, $state) {
var SF = appManager.state.SF;
var SO = appManager.state.SO;
$scope.productLineSelected = function (product) {
setProductLine(product);
};
function setProductLine(product) {
SF.setProduct(product);
$state.go('metricDashboard');
}
}]);
Here is the factory:
applicationManager.factory('appStateManager', ['$rootScope', '$sessionStorage', '$state', function ($rootScope, $sessionStorage, $state) {
// STATE OBJECT CLASSES
//
var stateClasses = {};
stateClasses.ProductLine = function (name) {
this.name = name;
this.dashboard = {
mode: 'reporting', //reporting, analysis
modeView: 'canvas', //canvas, data
index: {
report: 0,
userReport: 0,
canvas: 0,
group: 0,
element: 0,
filter: 0,
}
};
this.reports = [];
this.canvases = [new stateClasses.Canvas];
};
// STATE DATA FUNCTIONS
//
var stateFunctions = {};
stateFunctions.setProduct = function (product) {
session.StateObject.productLine.current = product.Code;
session.StateObject[product.Code] = (typeof session.StateObject[product.Code] === 'undefined') ? new stateClasses.ProductLine(product.Name) : session.StateObject[product.Code];
};
// STUCTURE
//
var stateScope = $rootScope.$new(true);
var session = $sessionStorage;
session.StateObject = (typeof session.StateObject === 'undefined') ? new stateClasses.StateObject : session.StateObject;
stateScope.SO = session.StateObject;
stateScope.SF = stateFunctions;
return stateScope;
}]);
Here is the controller trying to access the name:
metricDashboard.controller('MetricDashboard', ['$scope', 'appManager', function ($scope, appManager) {
var SF = appManager.state.SF;
var SO = appManager.state.SO;
DSO = SO[SO.productLine.current];
$scope.name = DSO.name;
}]);
I suspect that the issue is related to the order in which things are happening, however, I cannot figure out why it works 7 times out of 10.
When I do get the error, I have been able to determine that the line SO.productLine.current in the second controller has a value of none, meaning it doesn't seem to have been updated from the scope of the controller, however, at the same time, I'm also using console.log(JSON.stringify()) inside the factory, and the factory does indeed show a proper value instead of none.
I've also tried using $timeout on $state.go, and also tried passing it as a callback, however neither of those prevent the issue. Again 7 times out of 10, the code runs fine and the name property is value, but sometimes its not.
I was able to correct the problem with a few steps. The idea is to remove the assignment of the DSO variable from the MetricDashboard controller and move that functionality of assignment into the factory, then simply reference the newly assigned variable back in the controller.
Here are the changes:
In Factory
...
// STATE DATA FUNCTIONS
//
var stateFunctions = {};
stateFunctions.setProduct = function (product) {
session.StateObject.productLine.current = product.Code;
session.StateObject[product.Code] = (typeof session.StateObject[product.Code] === 'undefined') ? new stateClasses.ProductLine(product.Name) : session.StateObject[product.Code];
//new functionality for assignment
session.DynamicStateObject = session.StateObject[product.Code];
stateScope.DSO = session.DynamicStateObject;
};
// STUCTURE
//
var stateScope = $rootScope.$new(true);
var session = $sessionStorage;
session.StateObject = (typeof session.StateObject === 'undefined') ? new stateClasses.StateObject : session.StateObject;
//new structure to persist assignment beyond page refresh
session.DynamicStateObject = (typeof session.DynamicStateObject === 'undefined') ? {} : session.DynamicStateObject;
//new reference
stateScope.DSO = session.DynamicStateObject;
stateScope.SO = session.StateObject;
stateScope.SF = stateFunctions;
return stateScope;
In Controller
var SF = appManager.state.SF;
var SO = appManager.state.SO;
//Removed assignmnet
//DSO = SO[SO.productLine.current];
//Added reference
var DSO = appManager.state.DSO;
$scope.name = DSO.name;
While I have not yet tested the new code extensively, I have not been able reproduce the error.

Array populated witin 'service' but empty when referenced by any 'controller'

I have an AngularJS service which should get a JSON object and create three arrays based on differing criteria (all, searchable and has coordinates). These arrays need to be referenced by more than one controller, hence the use of a service.
When I test any of the three arrays the array within the service itself (as below), all three are correctly populated.
However, all three of my arrays are empty when referenced by any controller.
What am I missing here?
app.service('$stationsList', ['$http', function($http){
var stationsList = [],
searchableStations = [],
locatableStations = [];
$http.get('stations.json').then(function(res){ // Grab the JSON list of all stations
[].map.call(res.data || [], function(elm){ // Map all stations...
stationsList = res.data; // Set all stations to 'stationsList'
if(elm.link.indexOf(".xml") > -1) // Check to see if the station is searchable (has a full link)
searchableStations.push(elm); // It does - add the station to 'searchableStations'
if( // Check to see if the station can be checked as the closest station (has coordinates)
isFinite(parseFloat(elm.latitude)) &&
isFinite(parseFloat(elm.longitude))
)
locatableStations.push(elm); // It does - add the station to 'locatableStations'
});
console.log(stationsList);
console.log(searchableStations);
console.log(locatableStations);
});
return{
getList: function(){
return stationsList;
},
setList: function(value){
stationsList = value;
},
getSearchable: function(){
return searchableStations;
},
setSearchable: function(value){
searchableStations = value;
},
getLocatable: function(){
return locatableStations;
},
setLocatable: function(value){
locatableStations = value;
}
};
}]);
Example of how I'm referencing service -
app.controller('searchCtrl', ['$scope', '$http', '$localStorage', '$stationsList', function($scope, $http, $localStorage, $stationsList){
$scope.stationsList = $stationsList.getSearchable(); // Grab a list of all stations
$scope.selectStation = click_selectStation; // Handle clicks of a station within the 'searchCtrl' controller
$scope.localStorage = $localStorage.$default({ // Grab the local storage (so that it can be updated when the user selects a station)
recentStations: [] // Set a default value of '[]' for recentStations in case it doesn't exist
});
}]);
Edit
Derived from the answer posted by PankajParkar below, here is the service that will return the three arrays that I require.
However, my issue here is that every call to a method within the service triggers another async call to $http.get my JSON data. This is exactly what I was trying to avoid by using a service.
My desired outcome is one JSON call per page load, with my 3 arrays being created from that JSON call and then accessible to my controllers as and when required. If a service is not the correct answer, I am certainly open to other suggestions.
app.service('$stationsList', ['$http', function($http){
var searchableStations = [],
locatableStations = [];
/**
* Grab all stations (for the master list)
*/
var getAllStations = function(){
return $http.get('stations.json').then(function(res){ // Grab the JSON list of all stations
return res.data;
});
};
/**
* Grab only searchable stations (those with full links)
*/
var getSearchableStations = function(){
return $http.get('stations.json').then(function(res){ // Grab the JSON list of all stations
[].map.call(res.data || [], function(elm){ // Map all stations...
if (elm.link.indexOf(".xml") > -1) // Check to see if the station is searchable
searchableStations.push(elm); // It is - add the station to 'searchableStations'
});
return searchableStations;
});
};
/**
* Grab only locatable stations (those with coordinates)
*/
var getLocatableStations = function(){
return $http.get('stations.json').then(function(res){ // Grab the JSON list of all stations
[].map.call(res.data || [], function(elm){ // Map all stations...
if(
isFinite(parseFloat(elm.latitude)) &&
isFinite(parseFloat(elm.longitude))
) // Check to see if the station is locatable
locatableStations.push(elm); // It is - add the station to 'locatableStations'
});
return locatableStations;
});
};
return{
getAll: getAllStations,
getSearchable: getSearchableStations,
getLocatable: getLocatableStations
};
}]);
Your current code is failing because you made asynchronous ajax call & accepting value as soon as it made. That's why you are getting your values as undefined.
You need to wait till your ajax gets completed, that could be implemented using returning ajax promise to controller from service. So i'd suggest you to create a new method which will do $http ajax and will return promise from that function & that will execute .then function of controller that called the getSearchableStations. Below snippet will give you an Idea what I wanted to say.
Service
app.service('$stationsList', ['$http', function($http) {
var stationsList = [],
searchableStations = [],
locatableStations = [];
var getSearchableStations = function() {
return $http.get('stations.json').then(function(res) { // Grab the JSON list of all stations
[].map.call(res.data || [], function(elm) { // Map all stations...
stationsList = res.data; // Set all stations to 'stationsList'
if (elm.link.indexOf(".xml") > -1) // Check to see if the station is searchable (has a full link)
searchableStations.push(elm); // It does - add the station to 'searchableStations'
if ( // Check to see if the station can be checked as the closest station (has coordinates)
isFinite(parseFloat(elm.latitude)) &&
isFinite(parseFloat(elm.longitude))
)
locatableStations.push(elm); // It does - add the station to 'locatableStations'
});
console.log(stationsList);
console.log(searchableStations);
console.log(locatableStations);
return locatableStations; //return data from here.
});
};
return {
getList: function() {
return stationsList;
},
setList: function(value) {
stationsList = value;
},
getSearchable: function() {
return searchableStations;
},
setSearchable: function(value) {
searchableStations = value;
},
getLocatable: function() {
return locatableStations;
},
setLocatable: function(value) {
locatableStations = value;
},
//added new function
getSearchableStations: getSearchableStations
};
}]);
Inside you controller you will call service getSearchableStations method that does return promise, You will use .then function that would get called when promise get resolved. Same has been shown below with code.
Controller
app.controller('searchCtrl', ['$scope', '$http', '$localStorage', '$stationsList',
function($scope, $http, $localStorage, $stationsList){
$stationsList.getSearchableStations().then(function(data){
$scope.stationsList = data;
$scope.selectStation = click_selectStation; // Handle clicks of a station within the 'searchCtrl' controller
$scope.localStorage = $localStorage.$default({ // Grab the local storage (so that it can be updated when the user selects a station)
recentStations: [] // Set a default value of '[]' for recentStations in case it doesn't exist
});
}); // Grab a list of all stations
}]);

Reading data from firebase in angularfire

I have an app where I need to store artists and their details in database.Now I want to retrieve all the artists and render some of their details in front end.How to do that.
Secondly, if I get the artist rating in some input field by using ng-model, then how to store that value in a particular artist to update details.
The database structure is:
{
"artists": {
"Atif":{
"name":"atif",
"rating":8
},
"Himesh":{
"name":"himesh",
"rating":5
}
}
}
and this is angular.js
(function()
{
var app = angular.module("myapp", ["firebase"]);
app.controller("maincontroller", function($scope, $firebaseObject,$firebaseArray)
{
var ref = new Firebase("https://gigstart.firebaseio.com/");
var artists=ref.child("artists");
// download the data into a local object
$scope.data = $firebaseObject(ref);
// putting a console.log here won't work, see below
ref.on("value", function(snapshot)
{
console.log(snapshot.val());
}, function (errorObject)
{
console.log("The read failed: " + errorObject.code);
});
var artistsRef=new Firebase("https://gigstart.firebaseio.com//artists");
}); //end of controller
Now I want to render the name and rating of each artist in front end.Can I do something like
<div ng-repeat="artist in artists">
{{artist.name}}
{{artist.rating}}
</div>
You have a list of artists, which you want to ng-repeat over in your Angular view. You can accomplish that by:
app.controller("maincontroller", function($scope, $firebaseArray)
{
var ref = new Firebase("https://gigstart.firebaseio.com/");
var artists = ref.child("artists");
$scope.artists = new $firebaseArray(artists);
}
Please take a moment to go through the AngularFire quickstart before starting on your own project. This is covered in step 5.

Using Express to render an .ejs template for AngularJS and use the data inside AngularJS $scope

I hope I can explain myself with this first question I post on Stack Overflow.
I am building a small test application with the MEAN stack.
The application receives variable data from Mongoose based on an Express Route I have created.
For example the url is: localhost:3000/cities/test/Paris
Based on the name of the city the response gives me the name of the city and a description. I Know how to get this data inside the .ejs template
But thats not what I want. I want to use this data inside an ngRepeat.
Maybe this is not the right way but maybe you can help me figure this out.
The reason I want to do this is because I don't want a single page application but an Angular template that can be used over and over for each city and only uses the data that gets back from the mongoose find() results and not the whole cities array.
app.js :
var cityRoutes = require('./routes/cities');
app.use('/cities', cityRoutes);
app.set('views', './views'); // specify the views directory
app.set('view engine', 'ejs'); // register the template engine
./routes/cities/cities.js :
var express = require('express');
var citiesList = require('../server/controllers/cities-controller');
var bodyParser = require('body-parser');
var urlencode = bodyParser.urlencoded({ extended: false });
var router = express.Router();
// because this file is a fallback for the route /cities inside app.js
// the route will become localhost:3000/cities/test/:name
// not to be confused by its name in this file.
router.route('/test/:name')
.get(citiesList.viewTest)
module.exports = router;
../server/controllers/cities-controller.js :
var City = require('../models/cities');
module.exports.viewTest = function(request, responce){
City.find({ stad: request.params.name }, function(err, results){
if (err) return console.error(err);
if (!results.length) {
responce.json( "404" );
} else {
responce.render('angular.ejs', { messages:results });
// through this point everything works fine
// the angular.ejs template gets rendered correctly
// Now my problem is how tho get the results from the
// response.render inside the Angular directive
// so I can use the data in a $scope
}
});
};
../models/cities.js
var mongoose = require('mongoose');
module.exports = mongoose.model('City', {
stad: { type: String, required: true },
omschrijving: String
});
AngularJS directive :
// This is where I would like to use the messages result data
// so I can create a $scope that handles data that can be different
// for each url
// so basically I am using this directive as a template
app.directive('bestelFormulier', function () {
return {
restrict: 'E',
templateUrl: '/partials/bestel-formulier.html',
controller: ['$scope', '$http', '$resource', '$cookieStore',
function($scope, $http, $resource, $cookieStore){
// at this point it would be nice that the $scope gets the
// url based results. But I don't now how to do that..
// at this point the var "Cities" gets the REST API with
// all the cities...
var Cities = $resource('/cities');
// get cities from mongodb
Cities.query(function(results){
$scope.cities = results;
//console.log($scope.products);
});
$scope.cities = {};
}],
controllerAs: 'productsCtrl'
}
});
The database is stored like this :
[
{
stad: 'Paris',
omschrijving: 'description Paris',
},
{
stad: 'Amsterdam',
omschrijving: 'description Amsterdam',
}
]
I hope these files included helps explaining my issue.
Thanks in advance for helping me out
I figured out a way to do it...
The following changes to my code fixed my issue.
in app.js
var cityRoutes = require('./routes/cities');
app.use('/', cityRoutes);
// removed the name cities
./routes/cities/cities.js :
router.route('/cities/test/:name')
.get(citiesList.viewTest)
// added this route to use as an API
router.route('/api/cities/test/:name')
.get(citiesList.viewStad)
../server/controllers/cities-controller.js :
// added this callback so that a request to this url
// only responses with the data I need
module.exports.viewStad = function(request, responce){
City.find({ stad: request.params.name }, function(err, results){
if (err) return console.error(err);
if (!results.length) {
responce.json( "404" );
} else {
responce.json( results );
}
});
};
in my AngularJS app I added the $locationDirective and changed the following in my Angular directive to :
var url = $location.url();
var Cities = $resource('/api' + url);
// now when my .ejs template gets loaded the Angular part looks at
// the current url puts /api in front of it and uses it to get the
// correct resource
That is the way how I can use it in my $scope and use al the lovely Angular functionality :-)
Hope I can help other people with this... Eventually it was a simple solution and maybe there are people out there knowing beter ways to do it. For me it works now.

AngularJS nested functions in services and dependency injection?

Ok I have two modules which depend upon each other both modules have services, directives, ctrl's etc, now my question is how do i get values assigned in the nested function of the second module's service in the controller of the first service, I have added the dependencies to the first controller but i can't see to get at the nested functions variables to then manipulate them in the ctrl of the first module here's the code(considerably cut down):
angular.module("mainapp", [
"dateSheet",
"bookingApp"
]).controller("AppCtrl", [
"$scope",
"$attrs",
"Booking",
function (scope, source, attributes, AppDataLoader, booking, Booking) {
//HERE I NEED TO BE ABLE TO DO SOMETHING LIKE THIS
var getdaiyrate = function(){
var dumpDailyRates = scope.Booking.getalldates.getrates.dailyPrice
console.log(dumpDailyRates);
}
}
]);
angular.module("bookingApp", ["bookingApp.services",]);
angular.module("bookingApp.services").service("Booking", [
function(){
function getRate(source, dateSheet, dateSheetCtrl, expect, $$childTail, appData) {
var dateValue = $("Date", source).text() || "";
if (!dateValue) {
return null;
}
var dailyPrice = $("DailyPrice", source).text() || "";
var weeklyPrice = $("WeeklyPrice", source).text() || "";
var monthlyPrice = $("MonthlyPrice", source).text() || "";
var isAvailable = $("IsAvailable", source).text() === "1";
var minimumStay = Number($("MinimumStay", source).text());
if (isNaN(minimumStay)) {
minimumStay = DEFAULT_MINIMUM_STAY;
}
return {
date: new Date(dateValue),
dailyPrice: dailyPrice,
weeklyPrice: weeklyPrice,
monthlyPrice: monthlyPrice,
reserved: !isAvailable,
minimumStay: minimumStay
};
}
return {
getalldates: function(source, $scope){
return getRate(source, scope);
}
};
}
]);
The above doesn't work what am i doing wrong....
Could someone please send me in the direction of a decent tutorial that deals with a end to end app using various modules and dependencies??
Chris
You need to inject the service module into the module that you want to use it in. So the first line becomes
angular.module("mainapp", ["dateSheet","bookingApp","bookingApp.services"])
Also i don't see the creation of bookingApp.services so this may also be required
angular.module("bookingApp.services",[]);
and the invocation would be something like this
var dumpDailyRates = Booking.getalldates(sourceParameter, $scope);

Resources