I have built an AngularJS project before and am familiar with the syntax. This time around my ng-controller="UniversalCtrl as universal" is not working and I have tried everything. If I take universal.showHeader == true and change it to showHeader == true it works, but I need it to be the variable of universal. Like I said I have other projects following this same structure and they work fine.
Here is my HTML code:
<!DOCTYPE html>
<html>
<head lang="en">
<meta http-equiv="cache-control" content="no-store" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="pragma" content="no-store" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">
<link href="styles/MarkStrap.css" rel="stylesheet" />
<link href="styles/Site.css" rel="stylesheet" />
<script type="text/javascript" src="js/Angular/angular.min.js"></script>
<script type="text/javascript" src="js/Angular/angular-route.min.js"></script>
<script type="text/javascript" src="js/Universal/Universal.js"></script>
<script type="text/javascript" src="js/Universal/Filters.js"></script>
<script type="text/javascript" src="js/Universal/Directives.js"></script>
<title>WIN</title>
<link rel="shortcut icon" href="winIcon.ico">
</head>
<body ng-app="winApp" ng-controller="UniversalCtrl as universal">
<index-header ng-show="universal.showHeader == true"></index-header>
<ng-view></ng-view>
<script type="text/javascript" src="js/Applications/Applications.js"></script>
</body>
</html>
Here is my Universal.js setup:
(function () {
var winSystem = angular.module('winApp', ['ngRoute']);
winSystem.config(function ($sceProvider, $routeProvider) {
$routeProvider
.when('/Applications', {
templateUrl: "view-app.html",
controller: "AppController"
})
.otherwise({
templateUrl: "404.html"
})
});
winSystem.service("sharedData", function () {
var reloadData = false;
var beginAppLoad = false;
var reloadNotes = false;
self.httpGet = function (http, url, callback) {
http.get(baseUrl + url, {
headers: { "Session-Id": localStorage.ogSessionId }
}).success(function (data) {
callback(data);
}).error(function (data, status, headers, config) {
if (status == "401") {
localStorage.removeItem("ogSessionId");
localStorage.removeItem("ogUserId");
window.location.href = loginUrl;
}
});
};
self.httpPost = function (http, url, content, callback) {
http.post(baseUrl + url, {
Content: JSON.stringify(content)
}, {
headers: {
"Session-Id": localStorage.ogSessionId
}
})
.success(function (data) {
callback(data);
})
.error(function (data, status, headers, config) {
if (status == "401") {
localStorage.removeItem("ogSessionId");
localStorage.removeItem("ogUserId");
window.location.href = loginUrl;
}
});
};
});
winSystem.controller("UniversalCtrl", ['$scope', '$http', 'sharedData', function ($scope, $http, sharedData) {
var self = $scope;
self.sharedDataSvc = sharedData;
self.isLocal = false;
if (location.href.indexOf("localhost") > -1) {
self.isLocal = true;
} else self.isLocal = false;
self.account = {};
self.actions = [];
self.notifications = [];
self.alertCount = 0;
self.showAlert = false;
self.showHeader = true;
self.alertMessage = "";
}]);
})();
You are binding the models to the scope object instead of the controller instance.
Try:
winSystem.controller("UniversalCtrl", ['$http', 'sharedData', function ($http, sharedData) {
var self = this;
self.sharedDataSvc = sharedData;
self.isLocal = false;
if (location.href.indexOf("localhost") > -1) {
self.isLocal = true;
} else self.isLocal = false;
self.account = {};
self.actions = [];
self.notifications = [];
self.alertCount = 0;
self.showAlert = false;
self.showHeader = true;
self.alertMessage = "";
}]);
And i noticed that you are using self variable on the service sharedData but you haven't initialized it. Just the same 'var self = this;'
Related
i like to pass to a function pointer to function that the addEventListener will use .
if you run this you will get an error .
what is the "Javascript" way to pass a function pointer ( don't know how to call it ) to addEventListener ?
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="UTF-8">
<title>Title</title>
<style>
</style>
<script>
var data = {
"foo1" : "aaa",
"foo2" : "bbb",
"foo3" : "ccc"
}
var createLabel = function(mykey,func) {
var label = document.createElement('label');
label.innerHTML = mykey;
label.id = "lbl_"+mykey;
label.addEventListener("click", () =>{
self.func(mykey);
}, false);
document.getElementById("container2").appendChild(label);
var br = document.createElement('br');
document.getElementById("container2").appendChild(br);
};
var popolateDS = function() {
self = this;
var i = 0;
for(var key in data) {
(function () {
var mykey = key;
if (data.hasOwnProperty(key)) {
if(i==0) {
createLabel(key,dsOnClick1);
i++;
}
createLabel(key,dsOnClick2);
}
}()); // immediate invocation
}
}
var dsOnClick1 = function(key) {
alert("dsOnClick1 "+key);
}
var dsOnClick2 = function(key) {
alert("dsOnClick2 "+key);
}
</script>
</head>
<body>
<div id="container2">
</div>
<button onclick="popolateDS()">click</button>
</body>
</html>
You don't need to refer to this as self.func, you can just call func like below and it'll work as expected:
label.addEventListener("click", () =>{
func(mykey);
}, false);
I am trying to make a pure js mvc app where I update an h1 with the text of an input field. I got to the point that the the value of the input in the model can be logged nicely but for some reason the h1 is not changing at all.
Could you give me some help that why is that and how to solve it?
my code:
window.onload = function() {
var model = new Model();
var controller = new Controller(model);
var view = new View(controller);
};
function Model() {
this.inputtext = "zzzzz";
this.heading = this.inputtext;
console.log('model called');
};
function Controller(model) {
var controller = this;
this.model = model;
this.handleEvent = function(e) {
switch (e.type) {
case "click":
controller.clickHandler(e.target);
break;
case "input":
controller.keyupHandler(e.target);
break;
default:
console.log(e.target);
}
}
this.getModelHeading = function() {
console.log("from getmodel: " + controller.model.inputtext + "heading " + controller.model.heading);
return controller.model.heading;
}
this.keyupHandler = function(target) {
controller.model.inputtext = target.value;
controller.getModelHeading();
}
console.log('controller called');
};
function View(controller) {
this.controller = controller;
this.heading = document.getElementById("heading");
this.heading.innerHTML = controller.getModelHeading();
this.inputtext = document.getElementById("inputtext");
this.inputtext.addEventListener('input', controller);
console.log('view called');
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" : content="width=device-width">
<title>Vanilla MVC Framework</title>
<script type="text/javascript" src="./Config.js"></script>
<script type="text/javascript" src="./Model.js"></script>
<script type="text/javascript" src="./Controller.js"></script>
<script type="text/javascript" src="./View.js"></script>
</head>
<body>
<input id='inputtext' /></input>
<h1 id='heading'></h1>
</body>
</html>
You need to link the view to the controller, then modify the view from the controller.
window.onload = function() {
var model = new Model();
var controller = new Controller(model);
var view = new View(controller);
};
function Model() {
this.inputtext = "zzzzz";
this.heading = this.inputtext;
console.log('model called');
};
function Controller(model) {
var controller = this;
this.model = model;
this.handleEvent = function(e) {
switch (e.type) {
case "click":
controller.clickHandler(e.target);
break;
case "input":
controller.keyupHandler(e.target);
break;
default:
console.log(e.target);
}
}
this.getModelHeading = function() {
// console.log("from getmodel: " + controller.model.inputtext + "heading " + controller.model.heading);
controller.model.heading = controller.model.inputtext;
return controller.model.heading;
}
this.keyupHandler = function(target) {
controller.model.inputtext = target.value;
controller.view.heading.innerHTML=controller.getModelHeading();
}
console.log('controller called');
};
function View(controller) {
this.controller = controller;
this.heading = document.getElementById("heading");
this.heading.innerHTML = controller.getModelHeading();
this.inputtext = document.getElementById("inputtext");
this.inputtext.addEventListener('input', controller);
controller.view = this;
console.log('view called');
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" : content="width=device-width">
<title>Vanilla MVC Framework</title>
<script type="text/javascript" src="./Config.js"></script>
<script type="text/javascript" src="./Model.js"></script>
<script type="text/javascript" src="./Controller.js"></script>
<script type="text/javascript" src="./View.js"></script>
</head>
<body>
<input id='inputtext' />
<h1 id='heading'></h1>
</body>
</html>
You update the h1 element only in the constructor of View class.
In keyUp event handler you update the only model but you haven't reassigned the view.heading.innerHtml value.
Only your View should know about where in DOM to display a model.property. Therefore, my suggestion to you add this code in your View:
function View(controller) {
var _self = this;
this.controller = controller;
this.heading = document.getElementById("heading");
updateHeading.call(_self);
this.inputtext = document.getElementById("inputtext");
this.inputtext.addEventListener('input', function(e){
controler.handleEvent(e);
updateHeading.call(_self);
});
console.log('view called');
function updateHeading(){
this.heading.innerHTML = controller.getModelHeading();
}
}
In the following code I get an error: TypeError: i.Print is not a function when the button is clicked. What is the cause of this error, and how do I fix it? Using Firefox debugger when I look at the value of i in the button's click handler, I see that i.prototype.Print has value Outer/Inner.prototype.Print().
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<p id="prn">Value here</p>
<button id='btn'>Print</button>
<script src="https://code.jquery.com/jquery-1.12.4.min.js">
</script>
<script>
function TestObject(i)
{
$("#btn").on("click", function() {
i.Print();
i.Change(Math.random() * 10 + 5);
});
}
function TestPrototype()
{
var o = function Outer() {
function Inner(v)
{
var iv = v;
function print()
{
$("#prn").text(iv);
}
};
Inner.prototype.Print = function() {
print();
console.log(iv);
};
Inner.prototype.Change = function(nv) {
iv = nv;
};
return {
getInner : function(v) {
var i = Inner;
i(v);
return i;
}
};
}();
var i1 = o.getInner(10);
TestObject(i1);
}
;(function() {
TestPrototype();
}());
</script>
</body>
</html>
You need to create an object using the constructor,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<p id="prn">Value here</p>
<button id='btn'>Print</button>
<script src="https://code.jquery.com/jquery-1.12.4.min.js">
</script>
<script>
function TestObject(i)
{
$("#btn").on("click", function() {
i.Print();
i.Change(Math.random() * 10 + 5);
});
}
function TestPrototype()
{
var o = function Outer() {
function Inner(v)
{
// instatiate member variables
this.iv = v;
this.print = print;
function print()
{
$("#prn").text(this.iv);
}
};
Inner.prototype.Print = function() {
// access member variable
console.log(this.iv);
this.print();
print();
};
Inner.prototype.Change = function(nv){
iv = nv;
};
return {
getInner : function(v) {
var i = Inner;
return new i(v);
}
};
}();
var i1 = o.getInner(10);
TestObject(i1);
}
;(function() {
TestPrototype();
}());
</script>
</body>
</html>
Here is my code after simplified:
for (var i = 0; i < list.length; i++) { //list.length == 2.
var confirmPopup = $ionicPopup.confirm({
title: 'title',
template: 'confirming message'
});
console.log(i); // i == 0, which is correct.
confirmPopup.then(function (res) {
if (res) {
console.log(i); //i == 2, which is wrong, should be 0.
list[i].property = true; //property of undefined error occur here. Because i is 2, list.length is 2, so there's no list[2] actually.
}
else {
list[i].property = false; //same here.
}
});
}
So my issue is, I want to change list[i].property based on user's confirmation. But I don't know why the index changed from 0 to 2, I feel there's something to do with this comfirmPopup.then. Wondering how to fix this?
I don't know if I've understood you correctly but take a look at the snippet below.
The issues you had were the following:
You said that you have a list of numbers. Is that an array of numbers, or an array of objects? If it was just an array of numbers, that would explain why you're getting undefined. See the snippet for how I set up the array.
The main problem you're having is that you're trying to use i after confirmPopup.then(function (res) {, but by then, i will already have been destroyed. The res in confirmPopup.then(function (res) { is basically the result of your popup selection. This means that if you select "OK", then it will try to insert the value of i, by which time the loop will have already been terminated.
Maybe this will help you.
angular.module('ionicApp', ['ionic'])
.controller('Ctrl1', function($scope, $ionicPopup) {
var i = 0;
var list = [];
list = [{number: 123, property: false}, {number: 456, property: false}, {number: 678, property: true}];
var runPopUp = function() {
var confirmPopup = $ionicPopup.confirm({
title: 'title',
template: 'confirming message'
});
confirmPopup.then(function (res) {
if (res) {
list[i].property = true;
alert(list[i].number + " = " + list[i].property);
i++;
}
else {
list[i].property = false;
alert(list[i].number + " = " + list[i].property);
i++;
}
})
}
$scope.toggle = function() {
for (i; i < list.length; i++) {
runPopUp();
}
i = 0;
}
})
<html ng-app="ionicApp">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title>Ionic Template</title>
<link href="http://code.ionicframework.com/1.0.0-beta.2/css/ionic.css" rel="stylesheet">
<script src="http://code.ionicframework.com/1.0.0-beta.2/js/ionic.bundle.js">
</script>
</head>
<body ng-controller="Ctrl1">
</ion-content>
<div>
123 is false; 456 is false; 678 is true;
<button class="button button-small button-positive" ng-click="toggle()">Set Properties</button>
</div>
</ion-content>
</body>
</html>
Here's the nice solution:
Use list.forEach instead of for loop:
list.forEach(function (item) {
var confirmPopup = $ionicPopup.confirm({
title: 'title',
template: 'confirming message'
});
confirmPopup.then(function (res) {
if (res) {
item.property = true;
}
else {
item.property = false;
}
});
});
I'm trying to solve this issue: I have an array of objects, each containing an image property, which is an absolute url to a remote image.
I have to find the first object with an image larger than 500px, extract it from the array and putting it into another object.
What I've tried to do is to cycle through the array and call a function that loads the image and returns the width, but it doesn't work…
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, loadImages) {
var articles = [
{
"image": "http://i.res.24o.it/images2010/logo.gif"
},
{
"image": "http://www.avvenire.it/Commenti/PublishingImages/ImmaginiArticolo/Originali/gispponema_47548148.jpg"
},
{
"image": "http://i.dailymail.co.uk/i/pix/2012/03/07/article-2111440-1211004C000005DC-146_1024x615_large.jpg"
},
{
"image": "http://www.brookings.edu/~/media/research/images/w/wa%20we/wealthy002/wealthy002_16x9.jpg"
},
{
"image": "http://www.avvenire.it/Mondo/PublishingImages/ImmaginiArticolo/Originali/oREUVENRIV_47517580.jpg"
}
];
$scope.articles = loadImages.getCover(articles);
})
.factory('loadImages', function(){
function getMeta(url){
var img = new Image();
img.src = url;
img.onload = function(){
return img.width;
};
}
return {
getCover: function(articles) {
var cover = null;
for (var i = 0; i < articles.length; i++) {
if(articles[i].image){
var w = getMeta(articles[i].image);
if(w > 500){
cover = articles[i];
articles.splice(i,0);
}
}
}
return {
cover: cover,
articles: articles
};
}
};
});
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>{{articles}}!</p>
</body>
</html>
plunkr: http://plnkr.co/edit/tCacRy0jf9WhWreWIK7I
Do you have any suggestion? What am I doing wrong?
Thanks
Thanks to #JamesP comment I tried combining an asynchronous cycle found here (Asynchronous for cycle in JavaScript) and the $q promises in this way. I don't know if it's the best way to do it, but it works.
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, loadImages) {
var articles = [
{
"image": "http://placehold.it/200"
},
{
"image": "http://placehold.it/300"
},
{
"image": "http://placehold.it/600"
},
{
"image": "http://placehold.it/700"
},
{
"image": "http://placehold.it/800"
}
];
loadImages.asyncLoop(articles.length, function(loop){
var i = loop.iteration();
loadImages.getMeta(articles[i].image).then(function(r){
var cover = articles[i];
articles.splice(i,1);
$scope.articles = {
cover: cover,
articles: articles
};
}, function(){
loop.next();
})
}, function(){
$scope.articles = articles;
});
})
.factory('loadImages', function($q){
return {
getMeta: function(url){
var deferred = $q.defer();
try{
var img = new Image();
img.src = url;
img.onload = function(){
if(img.width > 500){
deferred.resolve(img.width);
}else{
deferred.reject();
}
}
}catch(e){
deferred.reject(e);
}
return deferred.promise;
},
asyncLoop: function(iterations, func, callback) {
var index = 0;
var done = false;
var loop = {
next: function() {
if (done) {
return;
}
if (index < iterations) {
index++;
func(loop);
} else {
done = true;
callback();
}
},
iteration: function() {
return index - 1;
},
break: function() {
done = true;
callback();
}
};
loop.next();
return loop;
}
};
});