AngularJs can't run a method - angularjs

I am a beginner angularjs user, but i have to learn it for my new job and I thought I could practice a bit. So I did a simple string reverse method and I thought I could make a simple calculator (exactly, only sum). Here is my code. I made 2 modules, 2 controllers and the first one is working fine, but the calculator isn't. However I made a simple site, where only the calc code is, and it works fine and I don't understand why it works, but doesn't work if 2 modules are on the same site.(Yeah, i'm a very beginner). Thank you for your help.
<!DOCTYPE html>
<html lang="en">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"> </script>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div ng-app="MyApp" ng-controller="myController">
<center>
<input type="text" ng-model="myString" placeholder="Enter text"/>
<p>Input: {{myString }}</p>
<p>Filtered input: {{getReverse()}}</p>
</center>
</div>
<br><br>
<center>
<div ng-app="MyCalc" ng-controller="myCalculate">
<input type="text" ng-model="firstNumber"><br>
<input type="text" ng-model="secondNumber"><br>
<p> Result: {{getResult()}}</p>
</div>
</center>
<script>
var reverse = angular.module("MyApp", []);
var calc = angular.module("MyCalc",[]);
reverse.controller('myController',function($scope){
$scope.myString = "";
$scope.getReverse = function(){
return $scope.myString.split("").reverse().join("");
}
});
calc.controller('myCalculate',function($scope){
$scope.firstNumber = 0;
$scope.secondNumber = 0;
$scope.getResult = function(){
return Number($scope.firstNumber)+Number($scope.secondNumber);
}
});
</script>

ng-app directive can be used just one time in page.
only one AngularJS application can be auto-bootstrapped per HTML document. The first ngApp found in the document will be used to define the root element to auto-bootstrap as an application. To run multiple applications in an HTML document you must manually bootstrap them using angular.bootstrap instead. (https://docs.angularjs.org/api/ng/directive/ngApp)
But you can bootstrap manually your app. Affect id on div that contains an angular app and add this to your script (https://plnkr.co/edit/ZTW7mXx3iXm803xdYod1?p=preview):
angular.bootstrap(document.getElementById('reverse'), ['MyApp']);
angular.bootstrap(document.getElementById('calc'), ['MyCalc']);
But I agree with Vikash, create more modules and less app :)

Normally, you should not use 2 angular app in a web page.
If you need to use different module, just make one depend on another.
Let's say your main module is MyApp and you need MyCalc's function, you do it like this (JsFiddle):
var calc = angular.module("MyCalc",[]);
calc.controller('myCalculate',function($scope){
$scope.firstNumber = 0;
$scope.secondNumber = 0;
$scope.getResult = function(){
return Number($scope.firstNumber)+Number($scope.secondNumber);
}
});
// Make MyApp module depend on MyCalc
var reverse = angular.module("MyApp", ["MyCalc"]);
reverse.controller('myController',function($scope){
$scope.myString = "";
$scope.getReverse = function(){
return $scope.myString.split("").reverse().join("");
}
});
And then in the HTML:
<body ng-app="MyApp">
<div ng-controller="myController">
<center>
<input type="text" ng-model="myString" placeholder="Enter text"/>
<p>Input: {{myString }}</p>
<p>Filtered input: {{getReverse()}}</p>
</center>
</div>
<br><br>
<center>
<div ng-controller="myCalculate">
<input type="text" ng-model="firstNumber"><br>
<input type="text" ng-model="secondNumber"><br>
<p> Result: {{getResult()}}</p>
</div>
</center>
</body>
P/s: If you really need to bootstrap 2 angular app in the same web page, you need to bootstrap it manually (JsFiddle):
angular.bootstrap(document.getElementById('calc'), ['MyCalc']);
calc is the id of the element you need to bootstrap the second app on
<div id="calc" ng-controller="myCalculate">

use ng-module instead of ng-app because ng-app can be used with one module in one page.
<div ng-module="MyModuleA">
<h1>Module A</h1>
<div ng-controller="MyControllerA">
{{name}}
</div>
<div ng-module="MyModuleB">
<h1>Just Module B</h1>
<div ng-controller="MyControllerB">
{{name}}
</div>
var moduleA = angular.module("MyModuleA", []);
moduleA.controller("MyControllerA", function($scope) {
$scope.name = "Bob A";
});
var moduleB = angular.module("MyModuleB", []);
moduleB.controller("MyControllerB", function($scope) {
$scope.name = "Steve B";
});

Use angular ng-modules to achieve this
here is the working [link] [1]
[1] http://jsfiddle.net/j5jzsppv/111/
<div ng-modules="MyModuleA, MyModuleB">
<div ng-controller="myController">
<input type="text" ng-model="myString" placeholder="Enter text"/>
{{myString}}
<p>Filtered input: {{getReverse()}}</p>
</div>
<div ng-controller="myCalculate">
<input type="text" ng-model="firstNumber"><br>
<input type="text" ng-model="secondNumber"><br>
<p> Result: {{getResult()}}</p>
</div>
var reverse = angular.module("MyModuleA", []);
var calc = angular.module("MyModuleB", []);
reverse.controller('myController', function ($scope) {
$scope.myString = "";
$scope.getReverse = function () {
return $scope.myString.split("")
.reverse()
.join("");
}
});
calc.controller('myCalculate', function ($scope) {
$scope.firstNumber = 0;
$scope.secondNumber = 0;
$scope.getResult = function () {
return Number($scope.firstNumber) + Number($scope.secondNumber);
}
});

Related

Writing an adding function in AngularJS

I'm new to AngularJS and I am doing some tutorials to get in touch with it. While I'm doing the tutorials I have modified the code a bit to get a better feeling of what's behind. My code consists of two parts, which have nothing to do with each other.
The first one is a simple user input and based on that a list gets filtered. This is working fine.
However, in the second part I was trying to implement a simple adding function where the user can give an input and based on that the sum of two numbers is calculated. This part is not working at all. The numbers are being recognised as strings. The code is basically from this source here. When I copy the whole code and run it, it works fine, but when I modify it a bit it doesn't.
I want to understand why my code isn't working. To me there is nearly no difference. So I think that I eventually misunderstood the concept of angularjs. But I can't figure out where the error could be.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script type="text/javascript">
function TodoCtrl($scope) {
$scope.total = function () {
return $scope.x + $scope.y;
};
}
</script>
</head>
<body data-ng-app>
<input type="text" ng-model="name">{{name}}
<div data-ng-init="Names=['Arthur', 'Bob', 'Chris', 'David', 'EDGAR']">
<ul>
<li data-ng-repeat="naming in Names | filter: name ">{{naming}}</li>
</ul>
</div>
<div data-ng-controller="TodoCtrl">
<form>
<input type="text" ng-model ="x">{{x}}
<input type="text" ng-model ="y"> {{y}}
<input type="text" value="{{total()}}"/>
<p type= "text" value="{{total()}}">value</p>
</form>
</div>
</body>
</html>
Several things to change...
First you need to create a module:
var app = angular.module("myApp", []);
Then you need to define a module e.g. myApp on the ng-app directive.
<body data-ng-app="myApp">
Then you need to add TodoCtrl to the module:
app.controller("TodoCtrl", TodoCtrl);
Also check that both $scope.x and $scope.y have values, and make sure that they are both parsed as integers, otherwise you will get string concatenation ("1"+"1"="11") instead of addition (1+1=2)!
$scope.total = function () {
return ($scope.x && $scope.y)
? parseInt($scope.x) + parseInt($scope.y)
: 0;
};
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script type="text/javascript">
(function(){
var app = angular.module("myApp", []);
app.controller("TodoCtrl", TodoCtrl);
function TodoCtrl($scope) {
$scope.total = function () {
return ($scope.x && $scope.y)
? parseInt($scope.x) + parseInt($scope.y)
: 0;
};
}
}());
</script>
</head>
<body data-ng-app="myApp">
<input type="text" ng-model="name">{{name}}
<div data-ng-init="Names=['Arthur', 'Bob', 'Chris', 'David', 'EDGAR']">
<ul>
<li data-ng-repeat="naming in Names | filter: name ">{{naming}}</li>
</ul>
</div>
<div data-ng-controller="TodoCtrl">
<form>
<input type="text" ng-model ="x">{{x}}
<input type="text" ng-model ="y"> {{y}}
<input type="text" value="{{total()}}"/>
<p type= "text" value="{{total()}}">value</p>
</form>
</div>
</body>
</html>
As mentioned in the above two answers adding TodoCtrl as controller instead function will make the snippet work.
REASON:
Angularjs framework above 1.3 does not support global function which means declaring controller as function wont work.
In your code snippet, you are using angular version 1.5, which needs the controller to be defined.
DEMO
angular.module("app",[])
.controller("TodoCtrl",function($scope){
$scope.x = 0;
$scope.y = 0;
$scope.total = function () {
return parseInt($scope.x) + parseInt($scope.y)
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" >
<input type="text" ng-model="name">{{name}}
<div data-ng-init="Names=['Arthur', 'Bob', 'Chris', 'David', 'EDGAR']">
<ul>
<li data-ng-repeat="naming in Names | filter: name ">{{naming}}</li>
</ul>
</div>
<div data-ng-controller="TodoCtrl">
<form>
<input type="text" ng-model ="x">{{x}}
<input type="text" ng-model ="y"> {{y}}
<input type="text" value="{{total()}}"/>
<p type= "text" value="{{total()}}">value</p>
</form>
</div>
</div>
you need to define the TodoCtrl as controller instead function
.controller("TodoCtrl",function($scope){
$scope.x = 0;
$scope.y = 0;
$scope.total = function () {
return parseInt($scope.x) + parseInt($scope.y)
};
})
Demo
angular.module("app",[])
.controller("TodoCtrl",function($scope){
$scope.x = 0;
$scope.y = 0;
$scope.total = function () {
return parseInt($scope.x) + parseInt($scope.y)
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" >
<input type="text" ng-model="name">{{name}}
<div data-ng-init="Names=['Arthur', 'Bob', 'Chris', 'David', 'EDGAR']">
<ul>
<li data-ng-repeat="naming in Names | filter: name ">{{naming}}</li>
</ul>
</div>
<div data-ng-controller="TodoCtrl">
<form>
<input type="text" ng-model ="x">{{x}}
<input type="text" ng-model ="y"> {{y}}
<input type="text" value="{{total()}}"/>
<p type= "text" value="{{total()}}">value</p>
</form>
</div>
</div>

Append chosen image to div tag and display one by one using ng-repeat in onclick button Angular JS

How to append choose images one by one to div tag using using ng-repeat when I click Add button after chosen file <input type="file"> in Angular JS. I have tried code below:
<body ng-app="myApp">
<div ng-controller="mainController">
<div>
<h3>Added Images: {{addedImages()}}</h3>
</div>
<div>
<input type="file" id="filename" ng-model="filename" name="">
<button ng-click="test()">Add Image</button>
<div class="shelfgallery"></div>
</div>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('mainController', function($scope) {
$scope.imageSources=[];
$scope.test = function(){
var url = ""//facing trouble in getting full URL of choosen image
alert(url);
$scope.imageSources.push({
imges: $scope.filename
});
var element = angular.element($('.shelfgallery'));
element.append('<img id="img_11" ng-repeat="imageSource in imageSources track by $index" ng-src="{{imageSource }}" /><br><br>');
//$compile(element)($scope);
};
$scope.addedImages = function(){
return $scope.imageSources.length;
}
});
</script>
</body>
If any wrong here let me know, or any other solution.

Dynamic Angular Js Not working via innerHTML

If I add a row with Dynamic Angular JS variable, it is not working.
Below is my code. Please help me let know the issue.
Also please note that the inner HTML in my original code is 600 lines long. In this example I have used simple div to simplify.
<div data-ng-init="quantity_r=1;price_r=5">
<h2>Cost Calculator Quantity:</h2>
<input type="number" ng-model="quantity_r"> Price: <input type="number" ng-model="price_r">
<div>
Total in dollar: {{quantity_r * price_r}}
</div>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script>
var app = angular.module('myApp', []);
app.controller('AppCtrl', function($scope) {
});
</script>
<script>
var app = angular.module('myApp1', []);
app.controller('AppCtrl', function($scope) {
angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
$scope.a = 1;
$scope.b = 2;
});
});
function replicateRegion() {
var table = document.getElementById("idTable");
var lastRow = table.rows.length;
var row = table.insertRow(lastRow);
var cell1 = row.insertCell(0);
var sHTML =document.getElementById("idTableTD1").innerHTML;
sHTML=sHTML.replace("_r", "_r" + lastRow.toString());
sHTML=sHTML.replace("Cost Calculator Quantity:", "Cost Calculator Quantity: Row Added " + lastRow.toString());
cell1.innerHTML = sHTML;
}
</script>
<div id="id1" ng-app="myApp" ng-controller="AppCtrl">
<button onclick="replicateRegion()">insert Row</button>
<table id="idTable">
<tr><td id="idTableTD1">
<div data-ng-init="quantity_r=1;price_r=5">
<h2>Cost Calculator Quantity:</h2>
<input type="number" ng-model="quantity_r"> Price: <input type="number" ng-model="price_r">
<div>
Total in dollar: {{quantity_r * price_r}}
</div>
</td></tr>
</table>
</div>
</body>
</html>
Only the first row which is static has the correct output. The rows added after button-click "Insert Row" have the problematic Angular JS output. Please help.
You need to add the code for replicateRegion() function inside the AngularJS controller and use the $compile service to bind the dynamically generated HTML into the AngularJS DOM.
var myapp = angular.module('myApp', []);
myapp.controller('AppCtrl', function ($compile, $scope) {
$scope.a = 1;
$scope.b = 2;
$scope.replicateRegion = function(){
var table = document.getElementById("idTable");
var lastRow = table.rows.length;
var row = table.insertRow(lastRow);
var template = `<div data-ng-init="quantity_r=1;price_r=5">
<h2>Cost Calculator Quantity:</h2>
<input type="number" ng-model="quantity_r"> Price: <input type="number" ng-model="price_r">
<div>
Total in dollar: {{quantity_r * price_r}}
</div>
</div>`;
var cell1 = row.insertCell(0);
template=template.replace(/_r/g, "_r" + lastRow.toString());
template=template.replace("Cost Calculator Quantity:", "Cost Calculator Quantity: Row Added " + lastRow.toString());
cell1.innerHTML = template;
$compile(cell1)($scope); //Now compile it to render the directive.
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div id="id1" ng-app="myApp" ng-controller="AppCtrl">
<button ng-click="replicateRegion()">insert Row</button>
<table id="idTable">
<tr><td id="idTableTD1">
<div data-ng-init="quantity_r=1;price_r=5">
<h2>Cost Calculator Quantity:</h2>
<input type="number" ng-model="quantity_r"> Price: <input type="number" ng-model="price_r">
<div>
Total in dollar: {{quantity_r * price_r}}
</div>
</div>
</td></tr>
</table>
</div>
Also notice that var template that specifies a generic template that should be inserted in the HTML dynamically on click. It is always a good practice to specify a static HTML template instead of extracting the generated HTML from the page and using that, which you have done.
When you add markup manually, like
document.getElementById('idTableTD1').innerHTML= '<div dynamic></div>'
you are bypassing all AngularJS code. You should do it rather as this:
angular.element("#idTableTD1").html('<div dynamic></div>');
may be this will help.

Angular Wiring up two controllers from Model to auto fill form

I've got an angular app I'm working on where I'm trying to auto fill a pop up modal based on a user's selection.
I thought I could use my model service to keep track of what the user selected and 'wire' the controller for the <select> list and it's edit button to the model but that doesn't seem to work.
Adding to the complexity I'm using angular-route and my <select> list is buried in a view. I was trying to keep my pop up modals in a separate controller outside the view because they've got their own templates and I had problems when I nested them into the view...
I've seen a few examples of wiring up angular apps and thought I understood them but I can't figure out what I'm doing wrong.
EDIT (thanks Pankaj Parkar for pointed out my mistakes in the plunker):
I have a plunker here:
https://plnkr.co/edit/6f9FZmV8Ul6LZDm9rcg9?p=preview
Below is the snipped in a single HTML page with CDN links :).
Am I just completely misunderstanding how angularjs is suppose to work?
<html ng-app="myApp">
<head>
<title>Bootstrap 3</title>
</head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<body>
<div ng-view></div>
<script id="editables.html" type="text/ng-template">
<div class="container">
<div class="jumbotron">
<form>
<div class="form-group">
<select class="form-control" id="mapsSelect" size="10" multiple ng-model="model.selected">
<option ng-repeat="n in editables">{{n}}</option>
<select>
</div>
<a href="#editModal" class = "btn btn-info" data-toggle="modal" ng-click="edit()" >Edit</a>
</form>
</div>
</div><!--end container div-->
</script>
<div ng-controller="modalsController">
<div id="editModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<form class="form-horizontal">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4>New Map</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="name" class="col-lg-3 control-label">Name</label>
<div class="col-lg-9">
<input type="text" class="form-control" id="name" ng-model="formModel.name"></input>
</div>
</div>
<div class="form-group">
<label for="desc" class="col-lg-3 control-label">Description</label>
<div class="col-lg-9">
<input type="text" class="form-control" id="desc" ng-model="formModel.desc"></input>
</div>
</div>
<div class="modal-footer">
<pre> {{ formModel | json }}<br><br>Working: {{ workingMap }}</pre>
Cancel
Continue
</div>
</form>
</div>
</div>
</div><!-- end modal -->
</div>
</body>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src = "https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular-route.min.js"></script>
<script src = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- <script src = "js/script.js"></script> -->
<script>
var app = angular.module('myApp', ['ngRoute']);
var modelService = function ($log){
var moduleHello = function(myMessage){
console.log("Module hellow from myService " + myMessage);
}
var moduleNames = {
"First" : {desc: "First's Description"},
"Second" : {desc: "Second's Description"},
"Third" : {desc: "Third's Description"}
};
var moduleWorkingName = {};
return {
hello: moduleHello,
editables: moduleNames,
workingName: moduleWorkingName
}
}//end modelService
app.factory("modelService", ["$log", modelService]);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/editables', {
controller: "editablesController",
templateUrl: "editables.html"
}).
otherwise({
redirectTo: "/editables"
});
}]);
app.controller('editablesController', ['$scope', '$log','modelService', function($scope,$log, $modelService) {
$scope.model = {};
//console.log( JSON.stringify( $modelService.editables ) );
$scope.editables = [];
for ( name in $modelService.editables){
$scope.editables.push( name );
}
$scope.edit = function(){
if ( typeof $modelService.editables [$scope.model.selected] != 'undefined'){
$modelService.workingName = $modelService.editables [$scope.model.selected];
console.log ("Setting my working name to " + JSON.stringify( $modelService.workingName ) );
}else{
console.log ("Nothing Selected");
}
}
}]);
app.controller('modalsController', ['$scope','modelService', function($scope,$modelService) {
$scope.formModel = {};
$scope.formModel.name = "Hard coding works of course";
$scope.formModel.desc = $modelService.workingName.desc; //But I can't seem to get this to update. I thought pointing it at an object in the Model would be enough.
console.log("Firing up modalsController");
}]);
</script>
</html>
I spent the last two days mulling over this in my head and I think I figured it out. For starters, here's the (working) plunker:
https://plnkr.co/edit/Kt3rebPtvGTt0WMXkQW4?p=preview
Now, the explanation. I was trying to keep a separate 'formModel' object that kept track of the controller's state. But that's both silly and pointless.
Instead what you're supposed to do is:
a. Create an object in your service to hold all your data (I just called this 'model')
b. For each controller that needs to share data create a variable on the $scope of the controller and point it to your 'model' variable from your service.
c. after that use the variables from your model in your html.
So in both my controllers you'll find this line:
$scope.model = $modelService.model;
and in my HTML you'll find stuff like this:
<input type="text" class="form-control" id="name" ng-model="model.workingName.name"></input>
notice how I'm using "model.workingName.name"? This references $scope.model.workingName.name, which thanks to the line $scope.model = $modelService.model from my JavaScript now points directly to my model.
And that is how you "wire up" Angular.
By the way, experienced Angular folks have probably noticed that this part:
$scope.editables = [];
for ( name in $modelService.model.names){
$scope.editables.push( name );
}
probably belongs in a directive instead of a controller because I'm editing the DOM.
Stuff like that's what makes it so hard to learn AngularJS. There's so many concepts to get the hang of.

How to dynamically create text box when we click on a link using angularjs

I have a problem to show INPUT field when do some action.
I have BUTTON (Click here) as soon as user made a click event on button i wanted to show input field
I have done this by using jQuery.
Can any one help me in Angular.js
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.boxShow = false;
});
</script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
show box
<div ng-show="boxShow">
<textarea rows="4" cols="50">text</textarea>
</div>
</div>
</div>
https://jsfiddle.net/bxwjpmaa/1/
HTML
<div class="btn btn-primary" ng-click="openTextBox();">Click Me To open text box</div>
<div ng-show="openTextBox == true">
<input type="text"/>
</div>
SCRIPT :
$scope.openTextBox = function () {
$scope.openTextBox = true;
}
please don't take scope variables and function names same
example here
$scope.openTextBox = function () {
$scope.openTextBox = true;
}
//this is not correct as per angular documentation because scope.openTextBox name already assigned to scope function,again its assigning scope variable "$scope.openTextBox = true" here u will get errors when ever u clicked div second time" TypeError: boolean is not a function" it will throw this error.so please dont use which is already assigned scope function dont assign scope variable
see this fiddle url : https://jsfiddle.net/veerendrakumarfiddle/bxwjpmaa/2/
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<ol>
<li ng-repeat="element in elements">
<input type="text" ng-model="element.value"/>
</li>
</ol>
<br/>
<b>Click here to add Textbox:</b><br/><input type="button" value="New Item" ng-click="newItem()"/>
<br/>
<br/>
<b>Click here to see ng-model value:</b><br/>
<input type="button" value="submit" ng-click="show(elements)">
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
var counter=0;
$scope.elements = [ {id:counter, value : ''} ];
$scope.newItem = function(){
counter++;
$scope.elements.push( { id:counter,value:''} );
}
$scope.show=function(elements)
{
alert(JSON.stringify(elements));
}
});
</script>
</body>
</html>

Resources