angular not 2-way binding - javascript

Trying to teach myself AngularJS and am stuck on a tutorial trying to build a simple shopping cart. I cannot for the life of me figure out why my {{}} angular tags are not displaying the data in the view, rather they are displaying the literal string (i.e. {{item.price | currency}}) Any insights? I'm worried the code isn't referencing the angular library, but the source is correct - the library is saved as angular.min.js .
Please help!
`
<html ng-app='myApp'>
<head>
<title>Your Shopping Cart </title>
</head>
<body ng-controller='CartController'>
<h1> Your order</h1>
<div ng-repeat='item in items'>
<span>{{item.title}}</span>
<input ng-model='item.quantity'>
<span>{{item.price | currency}}</span>
<span>{{item.price * item.quantity | currency}}</span>
<button ng-click="remove($index)">Remove</button>
</div>
<script type="text/javascript" src="angular.min.js"></script>
<script>
function CartController($scope){
$scope.items = [
{title: 'Paint pots', quantity: 8, price: 3.95},
{title: 'Polka dots', quantity: 17, price: 12.95},
{title: 'Pebbles', quantity: 5, price: 6.95}
];
$scope.remove = function(index){
$scope.items.splice(index, 1);
}
}
</script>
</body>
</html>`

When you set a value to ng-app (like ng-app="MyApp"), Angular.JS will expect you to have something like var myModule = angular.module("MyApp", []).
It will look for controllers only inside that, using myModule.controller() method (or can be directly after the module call). A global function will not work.
So, you have 2 options:
Replace <html ng-app="MyApp"> with <html ng-app>
Creating a module:
angular.module("MyApp", []).controller("CartController", function($scope) {
/// ...
});
Note that if you are using Angular.JS 1.3, you have to use method 2, as the global scope function way was removed in that version.

It is because CartController is just a plain function. You have to add it as a controller under the myApp module
angular.module("maApp", []).
controller("CartController", function ($scope) {
$scope.items = [
{title: 'Paint pots', quantity: 8, price: 3.95},
{title: 'Polka dots', quantity: 17, price: 12.95},
{title: 'Pebbles', quantity: 5, price: 6.95}
];
$scope.remove = function(index){
$scope.items.splice(index, 1);
}
})

I think you are trying this example from Angularjs Book, in which they have clearly mentioned that we are not initializing app for every example, you need to initialize your app. or simply ignore app, start coding from controller. when you mention ng-app="sample" you need to bootstrap that in order to work with controllers directives and everything that you use. In case if you dont want to initialize then you can simply leave ng-app="" blank. Here is working example [fiddle][1]
[1]: http://jsfiddle.net/kaLropns/

Related

AngularJS ng-repeat which has better performance - reassign values or filter value in controller

When using ng-repeat which approach has better performance? (assuming there are a large number of users)
Approach 1: Filter in Controller
<div ng-repeat="user in users | showBlocked">
<strong>{{user.id}}</strong>
<span>{{user.name}}
</div>
HTML code in template
$scope.users = [
{ id: 1, name: 'alex', isBlocked: true},
{ id: 2, name: 'john', isBlocked: true}
];
JavaScript code in Controller
showBlocked is a filter which returns a list of blocked users
.filter('showBlocked', function() {
return function(users) {
return users.filter(user => user.isBlocked);
}
});
Approach 2: Reassigns users list
<button ng-click="reassignUser(1)">reassign user</button>
<div ng-repeat="user in users">
<strong>{{user.id}}</strong>
<span>{{user.name}}
</div>
HTML code in template
$scope.reassignUser = function (userId) {
if (userId === 1) {
$scope.users = [{id: 1, name: 'alex', isBlocked: true}];
}
// in this case just assigns a single user
};
CodePen Demo: ng-repeat filter vs reassign binding
Do let me know if you need any additional information.
ng-repeat is evaluated on every $digest cycle, making it extremely slow with two-way data-binding due to $dirty checking. The best solution is to use one-way data-binding with {{:: data}} syntax.
But in your example it is indeed better to re-write the array rather than to filter it. The use of filters will work slower, due to each filter creating a sub collection of the original list. However, this can be resolved differently, by hiding the data with ng-show. Here is a post about the complex solution, but you can consider this simple example:
angular.module('myApp', []);
angular.module('myApp').controller('Ctrl', ['$scope', function($scope) {
$scope.users = [{name:"John", "id":0},
{name:"Adam", "id":1},
{name:"Ado", "id":2},
{name:"Chris", "id":3},
{name:"Heather", "id":4},
{name:"Stan", "id":5}];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="myApp" ng-controller="Ctrl">
ID: <input ng-model="query" />
<ul>
<li ng-repeat="user in users" ng-show="([user.id] | filter:query).length">
{{user.name}}
</li>
</ul>
</div>

Angular gemStore doesn't output anything

I'm currently trying out angularJS to see how it works.
I followed a tutorial on egghead.io which is quite good.
Came up with this fiddle but it annoys me that I cant find the issue/error.
Nothing shows/outputs
app.js
(function() {
var app = angular.module('gemStore', []);
app.controller('StoreController', function() {
this.products = gems;
});
var gems = [
{
name: "Soap",
price: 25,
quantity: 10,
canPurchase: false
},
{
name: "Bag",
price: 100,
quantity: 15,
canPurchase: false
}
];
});
index
<body ng-controller="StoreController as store">
<div ng-repeat="product in store.products">
<h1>{{product.name}}</h1>
<h2>${{product.price}}</h2>
<button ng-show="product.canPurchase">Add to cart</button>
</div>
This is the fiddle: https://jsfiddle.net/Vwsej/618/ (UPDATED)
Hope you could point me in the right direction.
In advance, thanks.
You forgot to include angular in your page. Simply add:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
to your HTML page. Note that jsfiddle has a button on the top left under "Frameworks & Extensions" that allows you to quick-add libraries such as angular.
You also forgot to call your IIFE:
(function() {
//Your JS...
})(); //<--- you forgot the ()
I forked your fiddle and fixed those issues, it works just fine.
You forgot to call the self calling function:
JS Fiddle:
https://jsfiddle.net/Vwsej/620/
This is how self calling structure is:
(function(){
// your js code to execute
})();//forgot to call

AngularJs crashes when trying to access data in directive

So I'm new to Angular and trying to do an app. My server is very basic and written in go. This is my angular code-
(function() {
var app = angular.module('dashboard', []);
app.controller("JobsController", function() {
this.currentJob = 0;
this.jobs = jobs;
this.setCurrentJob = function(index) {
this.currentJob = index;
};
});
var jobs = [
{
'id': 1,
'requester': 'Prakash Sanker',
'description': 'I want you to give me the entire world'
},
{
'id': 2,
'requester': 'MJ Watson',
'description': 'Please give me Spiderman, preferably upside down...but Im not fussy'
},
{ 'id': 3,
'requester': 'Josh Lyman',
'description': 'Matthew Santos as president...or Jed Bartlet..but please not anyone Republican'
},
{
'id': 4,
'requester': 'Barry Allen',
'description': 'A frictionless suit that wont burst into flames when I run at a zillion miles an hour...its for a friend'
},
{
'id': 5,
'requeter': 'A. Bambaata',
'description': 'Boombox, prime condition, from the 80s. Go back in time if you have to'
}
];
})();
This is my index.html -
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script type="text/javascript" src="/dashboard.js"></script>
<body>
<div class="dashboard">
<div ng-controller="JobsController as jobsCtrl">
<div class="jobs">
{{jobsCtrl.jobs[0]}}
</div>
</div>
</div>
</body>
This causes this error on my server
2015/07/29 12:18:02 http: panic serving [::1]:56857: runtime error: invalid memory address or nil pointer dereference
goroutine 18 [running]:
net/http.funcĀ·009()
/usr/local/go/src/pkg/net/http/server.go:1093 +0x9e
runtime.panic(0x20ed40, 0x4efaed)
/usr/local/go/src/pkg/runtime/panic.c:248 +0xda
html/template.(*Template).escape(0x0, 0x0, 0x0)
/usr/local/go/src/pkg/html/template/template.go:52 +0x30
Why is this happening?
You cannot use angular's default start {{ and end }} brackets in a go template because the go server interprets your angular as go template arguments and pipelines.
"Arguments" and "pipelines" are evaluations of data
To solve this you can make use of angular's $interpolate in your config to change the delimiters that define angular code:
var app = angular.module('dashboard', []);
app.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('[{');
$interpolateProvider.endSymbol('}]');
});
Alternatively if your pages are static you can just use Go's built in file server to not cause confusion with templates:
http://golang.org/pkg/net/http/#example_FileServer

How to bind an array or an object from a shared factory?

I have an Angular factory called Model which is shared across multiple controllers.
Basically this Model encapsulate properties and helpers methods.
I'm trying now to bind this model with my view and I have a strange behaviour, The nested objects of Model and the array of objects are not bind properly.
I think this issue is caused by the fact that i'm trying to modify an object inside an other object by reference. Maybe i have lost the context for the nested elements ?
How can i solve this problem ?
Here is my app :
var app = angular.module('plunker', []);
app.factory('Blog', function() {
function Blog(id) {
this.load(id);
}
Blog.prototype = {
name: "",
description: [{
value: ""
}, {
value: ""
}, {
value: ""
}],
website: {
name: "",
url: ""
},
load: function(id) {
},
helper1: function() {
// implementation
},
helper2: function() {
// implementation
}
// many other helpers...
}
return Blog;
});
app.controller('MainCtrl', function($scope, Blog) {
$scope.model = new Blog(12);
});
And finally my view
<!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 data-require="angular.js#1.2.x" src="https://code.angularjs.org/1.2.22/angular.js" data-semver="1.2.22"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Name <input ng-model="model.name"></p>
<div ng-repeat="line in model.description">
Description line {{$index}} <input ng-model="line.value">
</div>
<p>Website name <input ng-model="model.website.name"></p>
<p>Website url <input ng-model="model.website.url"></p>
<p>Result : {{ model | json }}</p>
</body>
</html>
To illustrate the problem, i have created a plunker example
When entering the values in the input fields, the Model is not updated with the changes. Only the field name is updated
Thanks in advance
Services are instanced by Angular and then a reference of them is injected where ever it is asked for.
Just change the code as following
var app = angular.module('plunker', []);
app.factory('Blog', function() {
return {
name: "",
description: [
{value: ""},
{value: ""},
{value: ""}
],
website: {
name: "",
url: ""
},
helper1: function() {
// implementation
},
helper2: function() {
// implementation
}
// many other helpers...
}
//return new Blog();
});
app.controller('MainCtrl', function($scope, Blog) {
$scope.model = Blog;
});
There is a slight difference in way in which services, factories and provider works. I hope you are clear on that other wise read this excellent article
http://tylermcginnis.com/angularjs-factory-vs-service-vs-provider/
NEW plunkr
http://plnkr.co/edit/FGOcPWVMeFDSyVtmv8Xd?p=preview
The factory exposes a new method using which you can create new instances of Blog.
I think its also because JSON filter is implemented you are not able to see all the values.
Because decription and website and url are in proto of the object, it's not displaying it.
I added a button for logging the model, you can see in the console that the value is changed
Edit 2
Q: I don't understand why the JSON filter is not displaying the values ?
A: I think it could be how its implemented, may be to make it light weight. Otherwise it has to walk through it's entire prototype chain
Q: Why the values are placed into the proto because of the nature of Blog ?
A: its because you add the values in the Blog's prototype and not inside Blog itself. It's how prototypical inheritence works in javascript. The advantage is think when you have to create 1000s of blog's instances. Now each instance can have the same methods and properties or to make it light weight, each instance can share the same object which is in its proto.(think of base class in OO language)
Read this for more clarity
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain
Blog here is a service that should be created by a factory. Your factory should return the new instance / a value / or a function.
You don't create an instance of the Blog that was injected to your controller, what is injected should already be the only instance available to everything that will be injected to others.
Hence, services are singleton (created by the factory).

passing json data from angular service to scope array in controller

I'm attempting to use ng-grid to display a table of data. However, I'm confused as how to place the data into the angular array to display, as examples show from angular-ui that this is the way to go. Below is a service defined for a rails api call
app.factory('ProviderMedicalService', ['$resource', function($resource) {
function ProviderMedicalService() {
this.service = $resource('/api/provider_medical_services/:providerMedicalServiceId', {providerMedicalServiceId: '#id'});
};
ProviderMedicalService.prototype.all = function() {
return this.service.query();
};
return new ProviderMedicalService;
}]);
this snippet of code was taken from a tutorial that integrates rails with angular. the $resource is the json data that is made from a custom rails api call. I'm assuming the return new ProviderMedicalServices returns the json data
(function() {
app.controller('ModalDemoCtrl', ['$scope', 'ProviderMedicalService', '$resource', '$modal', function($scope, ProviderMedicalService, $resource, $modal) {
$scope.provider_medical_services = ProviderMedicalService.all();
In the controller that wraps the table, the tutorial states that the $scope.provider_medical_services helps us extend the api later down the road.
currently my json data is displaying properly, except that it is not being formatted into the table format because of my setup.The following code is just what i'm trying to attempt, and i understand that the data should be inside the controller passed to the array
<div class="gridStyle" ng-grid="gridOptions">
<ul>
<li ng-repeat="service in provider_medical_services">
<p>{{service.name}} {{service.cash_price | currency}} {{service.average_price | currency}}</p>
<p></p>
<p></p>
</li>
</ul>
</div>
basically, my question is how do i pass from the factory into the array like this example?
$scope.myData = [{name: "Moroni", age: 50},
{name: "Tiancum", age: 43},
{name: "Jacob", age: 27},
{name: "Nephi", age: 29},
{name: "Enos", age: 34}];
$scope.gridOptions = { data: 'myData' };
})
edit for image because cant post image in comments
I'm guessing that instead of
$scope.gridOptions = { data: 'myData' };
you'll want
$scope.gridOptions = { data: 'provider_medical_services'};
I'll give you my example on passing the factory data
Javascript:
fruit = angular.module("fruit", []);
fruit.factory("Fruit", function() {
return {
fruits: [
{name: "Bananas", description: "Yellow and peely"},
{name: "Canteloupe", description: "Tell if its ripe by smelling them"},
{name: "Cherries", description: "Dont try to make jam out of sweet ones"},
{name: "Strawberries", description: "Picking them is murder on your back"},
{name: "Tomatoes", description: "People used to think they were poisonous" }
]
};
});
fruit.controller("FruitCtrl", function($scope, Fruit) {
$scope.fruits = Fruit.fruits;
});
HTML:
<!DOCTYPE html>
<html ng-app="fruit">
<head>
<meta name="description" content="Factory example" />
<script src="http://code.jquery.com/jquery.min.js"></script>
<link href="http://getbootstrap.com/2.3.2/assets/css/bootstrap.css" rel="stylesheet" type="text/css" />
<link href="http://getbootstrap.com/2.3.2/assets/css/bootstrap-responsive.css" rel="stylesheet" type="text/css" />
<script src="http://getbootstrap.com/2.3.2/assets/js/bootstrap.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body ng-controller="FruitCtrl">
<ul>
<li ng-repeat="fruit in fruits">{{fruit.name}}</li>
</ul>
</body>
</html>
edit in response to OP's comment below:
eg:
fruit.factory('Fruit', function($resource){
return $resource('http://localhost/folder1/fruitData.json');
});
Also need to inject the dependency of ['ngResource'] in the angular module
Also try this:
[To handle arrays with the $resource service, you can use the query method]
var fruitData= $resource('http://localhost/folder1/fruitData/');
$scope.items = fruitData.query();

Categories

Resources