AngularJS 2 OnSelect Returns Error - javascript

I'm trying to follow the Angular 2 tutorial, which is in TypeScript, but in JavaScript. Unfortunately I've hit a snag and I can't find a solution searching online. Right now I'm on the Master/Detail step. I'm defining an onSelect element but when I define my onSelect function I get back the following error:
Uncaught TypeError: Cannot read property 'annotations' of undefined
Here is my code:
app.component.js:
(function(app) {
app.AppComponent =
ng.core.Component({
selector: 'my-app',
template:`
<h2>My Heros</h2>
<ul class="heroes">
<li *ngFor="let hero of Heroes" [class.selected]="hero === selectedHero" (click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<div *ngIf="selectedHero">
<h2>{{selectedHero.name}} details!</h2>
<div><label>id: </label>{{selectedHero.id}}</div>
<div>
<label>name: </label>
<input [(ngModel)]="selectedHero.name" placeholder="name"/>
</div>
</div>
`
})
.Class({
constructor: function() {
this.title = 'Tour of Heros';
this.Heroes = Heroes;
this.onSelect(hero) {
this.selectedHero = hero;
};
}
});
})(window.app || (window.app = {}));
function Hero (id, name) {
this.id = id;
this.name = name;
};
var Heroes = [
new Hero(11, 'Mr. Nice'),
new Hero(12, 'Narco'),
new Hero(13, 'Bombasto'),
new Hero(14, 'Celeritas'),
new Hero(15, 'Magneta'),
new Hero(16, 'RubberMan'),
new Hero(17, 'Dynama'),
new Hero(18, 'Dr. IQ'),
new Hero(19, 'Magma'),
new Hero(20, 'Tornado')
];
index.html:
<html>
<head>
<title>Angular 2 QuickStart JS</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- 1. Load libraries -->
<!-- IE required polyfill -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/rxjs/bundles/Rx.umd.js"></script>
<script src="node_modules/#angular/core/bundles/core.umd.js"></script>
<script src="node_modules/#angular/common/bundles/common.umd.js"></script>
<script src="node_modules/#angular/compiler/bundles/compiler.umd.js"></script>
<script src="node_modules/#angular/platform-browser/bundles/platform-browser.umd.js"></script>
<script src="node_modules/#angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js"></script>
<!-- 2. Load our 'modules' -->
<script src='app/app.component.js'></script>
<script src='app/main.js'></script>
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
</body>
</html>
main.js:
(function(app) {
document.addEventListener('DOMContentLoaded', function() {
ng.platformBrowserDynamic.bootstrap(app.AppComponent);
});
})(window.app || (window.app = {}));
If I remove the this.onSelect(hero) {this.selectedHero = hero;}; it works fine, minus the ability to select an element. I've tried defining selectedHero with a default value and still the same error occurs. How do I define the onSelect function?

I guess
this.onSelect(hero) {
should be
this.onSelect = function (hero) {

Related

Access class properties in javascript from class method

this my first try doing the mvc model with classes in javascript.
With the method getFormValues() of the model object of my controller object app I want to read the values of all the input files . Then I want to save them to the form values property of the model object of my controller object. This doesn`t work!
The line console.log(app.model.getFormValues()); shows me the Array with the form values.
The line console.log(app.model.formValues); shows me an empty Array.
How can I store the array from the method getFormValues in the property formValues of the model object?
My HTML:
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<title>Hello, world!</title>
</head>
<body>
<form>
<div class="row">
<div class="col">
<input type="text" class="form-control" placeholder="First name">
</div>
<div class="col">
<input type="text" class="form-control" placeholder="Last name">
</div>
</div>
</form>
<button id="verification"> Verify</button>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="js.js"></script>
</body>
</html>
My JS/Jquery:
class Model {
constructor() {
this.formValues = this.getFormValues();
}
getFormValues() {
let $inputs = $("input");
var formValues = [];
$inputs.each(function(index) {
let value1 = $(this).val();
formValues.push(value1);
});
return formValues;
}
}
class View {
constructor() {}
}
class Controller {
constructor(model, view) {
this.model = model
this.view = view
}
}
const app = new Controller(new Model(), new View());
check = function () {
console.log(app.model.getFormValues());
console.log(app.model.formValues);
}
$("#verification").on("click", check);
Greetings and thanks in advance
Fabian
Your problem is based on the creation of the app constant.
You create the app constant when you first load the page.
At this point the inputs are empty so are they for the app constant.
Edit: update your variable when you click your button like in my snippet.
class Model {
constructor() {
this.formValues = this.getFormValues();
}
getFormValues() {
let $inputs = $("input");
var formValues = [];
$inputs.each(function(index) {
let value1 = $(this).val();
formValues.push(value1);
});
return formValues;
}
}
class View {
constructor() {}
}
class Controller {
constructor(model, view) {
this.model = model
this.view = view
}
}
const app = new Controller(new Model(), new View());
check = function () {
app.model.formValues = app.model.getFormValues();
console.log(app.model.getFormValues());
console.log(app.model.formValues);
}
$("#verification").on("click", check);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<div class="row">
<div class="col">
<input type="text" class="form-control" placeholder="First name">
</div>
<div class="col">
<input type="text" class="form-control" placeholder="Last name">
</div>
</div>
</form>
<button id="verification"> Verify</button>

Angular 2: Binding with JS without Node.js

I'm using last available public version (beta17) and I can't understand why a simple binding (convert by fly) doesn't work there.
What's the problem with the plnkr?
http://plnkr.co/edit/PfAUb5hOvgTcn0vbOdG1
index.html
<!doctype html>
<meta charset='utf-8'/>
<html>
<head>
<!-- CSS -->
<link rel='stylesheet' href='assets/bootstrap4.0.0-alpha.4/css/bootstrap.css' type="text/css"/>
<!-- Angular libraries -->
<script src="https://code.angularjs.org/2.0.0-beta.17/angular2-polyfills.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.17/Rx.umd.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.17/angular2-all.umd.dev.js"></script>
<!-- Angular app modules -->
<script src='app/app.js'></script>
<script src="app/components/converter/converter.js"></script>
</head>
<body align='center'>
<h1>Temperature Converter using Angular 2</h1>
<converter class='converter'></converter>
</body>
</html>
/app/app.js
'use strict';
(function (app) {
document.addEventListener('DOMContentLoaded', () => {
ng.platform.browser.bootstrap(app.ConverterComponent);
});
})(window.app || (window.app = {}));
/app/components/converter/converter.js
(function (app) {
app.ConverterComponent = ng.core
.Component({
selector: 'converter',
templateUrl: '/app/components/converter/template.html'
})
.Class({
constructor: function () {
this.temperature = '';
let temp = this.temperature;
temp = parseInt(temp, 10);
this.fahrenheit = ((9 / 5) * temp) + 32;
this.kelvin = (temp + 273.15);
}
})
})(window.app || (window.app = {}));
/app/components/converter/template.html
<div class="box">
<div>
<label for="temp">Enter your temperature (ºC):</label>
<br>
<input id="temp" [(ngModel)]="temperature" class="textfield">
</div>
<div [hidden]="temperature">
Waiting for your temperature...
</div>
<div [hidden]="!temperature">
<h3>{{fahrenheit}} ºF</h3>
<h3>{{kelvin}} K</h3>
</div>
</div>
You have to make your all the URL's to be started without / like app/app.js instead of /app/app.js
Here is Plunkr
Note: I would suggest you to use Angular 2 Final version instead of using old version

0x800a139e - JavaScript runtime error: [ng:areq] Argument 'timesheetListCtrl' is not a function, got undefined

I cant get this simple angular app to work. I know I am probably doing something silly. If anyone can help I would greatly appreciate it.When I run it I'm getting the following error:
0x800a139e - JavaScript runtime error: [ng:areq] Argument 'timesheetListCtrl' is not a function, got undefined
index.html
<!DOCTYPE html>
<html>
<head lang="en">
<!-- Style sheets -->
<link href="Content/bootstrap.css" rel="stylesheet" />
</head>
<body ng-app="timesheetManagement">
<div class="container">
<div ng-include="'app/HTML/timesheetListView.html'"></div>
</div>
<!-- Library Scripts -->
<script src="scripts/angular.js"></script>
<script src="Scripts/angular-resource.js"></script>
<!-- Application Script -->
<script src="app/app.js"></script>
<!-- Services -->
<script src="common/common.services.js"></script>
<script src="common/timesheetResource.js"></script>
<!-- Product Controllers -->
<script src="app/HTML/"></script>
</body>
</html>
timesheetListView.html
<div class="panel panel-primary"
ng-controller="timesheetListCtrl as vm">
<div class="panel-heading"
style="font-size:large">
Product List
</div>
app.js
(function () {
"use strict";
var timesheetManagement = angular
.module("timesheetManagement",
["common.services"]);
}());
timesheetListCtrl.js
(function () {
"use strict";
angular
.module("timesheetManagement")
.controller("timesheetListCtrl",
["timesheetResource", timesheetListCtrl]);
function timesheetListCtrl(timesheetResource) {
var vm = this;
timesheetResource.query(function (data) {
vm.timesheets = data
});
}
}());
So, it turns out you have to include timesheetListCtrl.js in index.html

Updating a variable inside Service

Right I've got a really dumb one for you, and I've been looking at this code all day with no result.
I have a simple textbox which goes through a controller and updates a variable inside a service (The service will eventually fetch/update data from somewhere else).
At the moment, I am able to retrieve the variable value all the way to the view and it works, but the textbox is unable to update the variable inside the service in order to then display the new variable value in the view again....
I really appreciate any help and hope I have made sense!!!
// APP/APP.JS
(function(){
var app = angular.module('appMod', ['ngRoute', 'ngAnimate']);
app.config(function ($routeProvider) {
$routeProvider
.when('/',
{
controller: 'introController',
templateUrl: 'app/partials/intro.html'
})
.otherwise({ redirectTo: '/' });
});
app.controller('nameController', function($scope, dataService) {
var nameValue;
this.name = dataService.getName();
this.submitName = function(nameVal) {
nameValue = this.nameCtrl.nameVal;
dataService.setName(nameValue);
};
});
app.controller('introController', function($scope, dataService) {
this.name = dataService.getName();
});
app.service('dataService', function () {
var name = "f";
this.getName = function() {
return name;
};
this.setName = function(nameVal) {
name = nameVal;
};
});
})();
<!-- INDEX.HTML -->
<!DOCTYPE html>
<html ng-app="appMod">
<head>
<link rel="stylesheet" type="text/css" href="content/css/normalize.css">
<link rel="stylesheet" type="text/css" href="content/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="content/css/style.css">
<link rel="stylesheet" type="text/css" href="content/css/animation.css">
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="scripts/bootstrap.min.js"></script>
<script type="text/javascript" src="scripts/angular.min.js"></script>
<script type="text/javascript" src="scripts/angular-route.min.js"></script>
<script type="text/javascript" src="scripts/angular-timer.min.js"></script>
<script type="text/javascript" src="scripts/angular-animate.min.js"></script>
<script type="text/javascript" src="app/app.js"></script>
</head>
<body>
<div class="container">
<div class="row" ng-controller="nameController as nameCtrl">
<img src="content/images/sitelogo.png" class="logo">
<h2 class="welcomeMessage fade">Welcome <span class="fade" ng-show="!nameCtrl.name == ''">{{nameCtrl.name}}</span><span class="inline fade" ng-hide="nameCtrl.name !== ''">Friend</span> <small>(We like to get personal!)</small></h2>
<div class="namebox fade">
<h2>Welcome <small class="fade">Please type your name</small></h2>
<form class="fade">
<div class="form-group">
<input type="text" class="form-control" ng-model="nameCtrl.nameVal" autofocus>
</div>
<button type="submit" style="width:100%;" class="btn btn-default fade" ng-click="nameCtrl.submitName()" >Submit</button>
</form>
</div>
</div>
</div>
<div ng-view></div>
</body>
</html>
You need to be binding to name and not nameVal on your input
Then just pass that in your setName call, i don't think the rest of the code is needed in there, you can get rid of the nameValue var too.
this.submitName = function() {
dataService.setName(this.name);
};
The nameValue var is local to the controller and not available on the $scope to bind to your view, so even though you were changing it, the view didn't know about it as it couldn't see that var.

backbone.js routing issue

I am very new to js and backbone.js, and I assure you I have searched extensively in docs and on here. I am trying to build a simple site that displays photos (eventually other things) and I want to be able to click a photo to see a different 'page' with another view/template. I cant seem to get this to work and now I am getting a "Uncaught TypeError: Cannot call method 'get' of undefined" in my router's photoById method. Code below... THANKS!
//------ main.js
var photoListTemplate = Handlebars.compile($('#photo-list-template').html());
var photoTemplate = Handlebars.compile($('#photo-template').html());
var navTemplate = Handlebars.compile($('#navigation-template').html());
var Photo = Backbone.Model.extend({
defaults: function() {
return {
};
},
initialize: function(options) {
}
});
var PhotoCollection = Backbone.Collection.extend({
model: Photo
});
var PhotoView = Backbone.View.extend({
events: {
},
//tagName: 'td',
className: 'photo',
template: photoTemplate,
initialize: function(options) {
_.bindAll(this, 'render');
this.model.on('change', this.render);
},
render: function() {
$(this.el).empty().append(this.template(this.model.toJSON()));
return this;
}
});
var PhotoCollectionView = Backbone.View.extend({
tagName: 'table',
className: 'photo-list',
template: photoListTemplate,
events: {
},
initialize: function(options) {
this.collection.on('add remove', this.render, this);
},
render: function() {
$(this.el).empty();
this.collection.each(function(photo){
$(this.el).append(new PhotoView({model: photo}).render().el);
}, this);
return this;
}
});
var PhotoRouter = Backbone.Router.extend({
routes: {
"": "list",
"photo/:id": "photoById"
},
initialize: function(options) {
},
allPhotos: function() {
this.photoList = new PhotoCollection();
this.photoCollectionView = new PhotoCollectionView({collection: this.photoList});
this.photList.fetch();
$('#content').empty().append(this.photoCollectionView.render().el);
},
photoById: function(id){
this.photo = this.photoList.get(id);
this.photoView = new PhotoView({model: this.photo});
$('#content').empty().append(this.photoView.render().el);
}
});
var photos = null;
$.getJSON('http://localhost:3000/photos.json', function(response){
photos = new PhotoCollection(response);
$('#container').append(new PhotoCollectionView({collection: photos}).render().el);
var photoRouter = new PhotoRouter();
Backbone.history.start();
});
/----- index.html
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/bootstrap.css">
<link rel="stylesheet" href="css/main.css">
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
</head>
<body>
<!--[if lt IE 7]>
<p class="chromeframe">You are using an <strong>outdated</strong> browser. Please upgrade your browser or activate Google Chrome Frame to improve your experience.</p>
<![endif]-->
<!-- Add your site or application content here -->
<!-- <p>Replace Me! Replace Me!</p> -->
<div class='container' id='container'>
</div>
<script type="text/x-handlebars-template" id='navigation-template'>
<div class='navbar'>
<div class='navbar-inner'>
<a class='brand' href=#>ohayon</a>
<ul class='nav'>
</ul>
</div>
</div>
</script>
<script type="text/x-handlebars-template" id='photo-template'>
<div class='lead'>
<a href='#photo/{{id}}'>{{name}}</a>
<img src='http://localhost:3000{{image.url}}' height='200' width='200'>
</div>
</script>
<script type="text/x-handlebars-template" id='photo-list-template'>
<div class='lead'>
<a href='#photos/{{id}}'>{{name}}</a>
<img src='http://localhost:3000{{image.url}}'>
</div>
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.8.2.min.js"><\/script>')</script>
<script src="js/plugins.js"></script>
<!-- If we want Boostrap components -->
<script src="js/bootstrap.js"></script>
<!-- Templating with Handlebars -->
<script src="js/handlebars.js"></script>
<!-- We Need Underscore.js -->
<script src="js/underscore.js"></script>
<!-- And Finally Backbone -->
<script src="js/backbone.js"></script>
<!-- Your Code goes here -->
<script src="js/main.js"></script>
<!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
<script>
var _gaq=[['_setAccount','UA-XXXXX-X'],['_trackPageview']];
(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
s.parentNode.insertBefore(g,s)}(document,'script'));
</script>
</body>
</html>
The way you've got it coded, there's no guarantee this.photoList will have been created by the time you attempt to use it in photoById. You might want to create it in the router's init function:
initialize: function(options) {
this.photoList = photos;
},
Also remove a few lines from allPhotos -- you don't want to re-create PhotoCollection or call fetch, since it was already created and populated in the first step of your app. Should look like this:
allPhotos: function() {
this.photoCollectionView = new PhotoCollectionView({collection: this.photoList});
$('#content').empty().append(this.photoCollectionView.render().el);
},
(One other problem, you're using container sometimes and content others.)
It's running here. (I used some dummy data to test with.)

Categories

Resources