What's the Angular way to update the scope? - javascript

I have a simple two-way binding setup with angular, and I added a plain javascript function that updates the value based off of the "alt" tag of an image a user clicks on. The problem is that when I hit save, the data doesn't update until I click inside the textbox and add a space. What's the best way to get around this?
http://plnkr.co/edit/j6tPYYUqvRyvfs32mcrW?p=preview
angular.module('copyExample', [])
.controller('ExampleController', ['$scope',
function($scope) {
$scope.master = {};
$scope.update = function(user) {
// Example with 1 argument
$scope.master = angular.copy(user);
};
$scope.reset = function() {
// Example with 2 arguments
angular.copy($scope.master, $scope.user);
};
$scope.reset();
}
]);
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
</head>
<body ng-app="copyExample">
<div ng-controller="ExampleController">
<form novalidate class="simple-form">
Name:
<input type="text" ng-model="user.name" id="name" />
<br />
<img src="http://placehold.it/100&text=John" onclick="changeText(alt)" alt="John" />
<br />
<button ng-click="reset()">RESET</button>
<button ng-click="update(user)">SAVE</button>
</form>
<pre>form = {{user | json}}</pre>
<pre>master = {{master | json}}</pre>
</div>
<script>
function changeText(value) {
document.getElementById('name').value = value
}
</script>
</body>
</html>

working fiddle - http://jsfiddle.net/lwalden/b2p7pu7g/
If you are already using Angular then don't write a plain vanilla javascript function for the image click event - use Angular.
Also it's recommended not to use the alt attribute in this way. You could use a data- attribute instead.
Additional attributes within a tag to pass values to a function

Related

Parameter not passed to next page - AngularJS

I want to pass a parameter to the next page onclick of a button.
I have tried as below; on the first page I have a textarea and I want to pass that value to the next page on button click using AngularJS, I have tried as below, but it's not working.
index.html
<!doctype html>
<html ng-app="project">
<head>
<title>Angular: Service example</title>
<script src="http://code.angularjs.org/angular-1.0.1.js"></script>
<script src="sample.js"></script>
</head>
<body>
<div ng-controller="FirstCtrl">
<h2>{{name}}</h2>
<input ng-model="thing.x"/>
</div>
<input type="button" value="send" onclick="send()">
<script>
function send(){
window.location ="second.html";
}
</script>
</body>
</html>
sample.js
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
var projectModule = angular.module('project',[]);
projectModule.factory('theService', function() {
return {
thing : {
x : 100
}
};
});
function FirstCtrl($scope, theService) {
$scope.thing = theService.thing;
$scope.name = "First Controller";
}
function SecondCtrl($scope, theService) {
$scope.someThing = theService.thing;
$scope.name = "Second Controller!";
}
second.html
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
<head>
<title>Passed data</title>
<script src="sample.js"></script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div ng-controller="SecondCtrl">
<h2>{{name}}</h2>
<input ng-model="someThing.x"/>
</div>
<br>
</body>
</html>
Please can you help me to figure it out?
First read this https://docs.angularjs.org/guide/$location
Remove send() function
function FirstCtrl($scope, $location, theService) {
$scope.thing = theService.thing;
$scope.name = "First Controller";
$scope.send = function(){
$location.path('/second').search({id: 12});
};
}
<input type="button" value="send" ng-click="send()">
To send the parameter to next page you have to use $location service.
$location.path('/second').search({id: 12});
But again this will not work for you as you are not using AngularJS for routing , you are using JS for that. I suggest following this PhoneCatApp to learn Angular basics

ajax call on angularjs

I am trying to validate a number input using angularjs.
The page works as desired by itself, however it does not work when I call the page with ajax.
Any help or advice would be appreciated!
Working angularjs jlgtest3.jsp ...
<div ng-app="total">
<script>
angular.module('total', [])
.controller('totalController', ['$scope', function($scope) { }]);
</script>
<form name="totalForm" ng-controller="totalController">
<input name="totalHours" ng-model="total" type="number" value="" />
<p ng-show="totalForm.totalHours.$error.number">Not valid number!</p>
</form>
</div>
</html>
Not working with ajax call (jlgtest4.jsp calling jlgtest3.jsp)...
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
function newajax() {
var xRequest1;
if(window.XMLHttpRequest)
{
xRequest1=new XMLHttpRequest();
} else {
xRequest1=new ActiveXObject("Microsoft.XMLHTTP");
}
xRequest1.onreadystatechange=function ()
{
if((xRequest1.readyState==4) && (xRequest1.status==200))
{
document.getElementById("test").innerHTML=xRequest1.responseText;
}
}
var urlencode = "jlgtest3.jsp";
xRequest1.open("post",urlencode,true);
xRequest1.send();
}
</script>
</head>
<input type="button" onclick="newajax()" value="button" />
<div id="test">
</div>
</html>
I attempted the angular ajax call as some people suggested, but I couldnt get it to work...
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<div ng-app="total">
<script>
angular.module('total', [])
.controller('totalController', ['$scope', function($scope) {
$http.POST("jlgtest3.jsp").then(function(response) {
$scope.test = response.data;
});
}]);
</script>
<div ng-controller="totalController">
<input type="button" value="button" />
{{test}}
</div>
</div>
</html>
If you're using Angular, you should consider using the $http service or even the $resource service. These both abstract ajax requests into a much simpler form. So instead of
xRequest1.open("post",urlencode,true);
xRequest1.send();
...etc...
You might have something like:
$http.POST(urlencode).then(function(response) {
document.getElementById("test").innerHTML=response.data;
// do other stuff with the response
});
And that will encapsulate essentially your entire newajax function.
As for #messerbill 's answer, you should not be making $http calls in your controller. These are better utilized within a service or factory that you then inject into your controller. Controllers are for business logic and should not deal with fetching and sending data.
you also can use a standart Ajax call but better use the $http angular way. You should call it inside of your angular controller.
XMLHttpRequest is an object used by Ajax - https://en.wikipedia.org/wiki/XMLHttpRequest
https://docs.angularjs.org/api/ng/service/$http
updated answer
Why dont you use Angular in the way its meant to be used? You should send your post inside of you angular service or controller. Don't manipulate your DOM if you use AngularJS like you did here:
document.getElementById("test").innerHTML=response.data;
istead you should do it that way:
angular.module('total', [])
.controller('totalController', ['$scope', function($scope) {
$http.POST("yourURL").then(function(response) {
$scope.test = response.data;
});
}]);
//template
<input type="button" value="button" />
<div ng-controller="totalController">
{{test}}
</div>
</html>
I have not tested it yet, but it should work - next time create a fiddle ;)
I posted this question again, but a little bit more simplified and Moncef Hassein-bey was able to answer my question Use Ajax to put external angularjs element in html page
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
angular.module('myApp', [])
.controller('myController', ['$scope', function($scope) { }]);
</script>
<script>
function newajax() {
var xRequest1;
xRequest1=new XMLHttpRequest();
xRequest1.onreadystatechange=function ()
{
if((xRequest1.readyState==4) && (xRequest1.status==200))
{
document.getElementById("test").innerHTML=xRequest1.responseText;
angular.bootstrap(document.getElementById('test'), ['myApp']);
}
}
xRequest1.open("post","jlgtest.html",true);
xRequest1.send();
}
</script>
<input type="button" value="button" onClick="newajax()" />
<div id="test">
</div>
</div>
</html>
Basically I needed to add the angular.bootstrap line of code, and the angular.module(... script needed to be in my main page
this is the called page code...
<html>
<div ng-app="myApp">
<form name="myForm" ng-controller="myController">
<input name="numberField" ng-model="myModel" type="number" value="" />
<p ng-show="myForm.numberField.$error.number">Not valid number!</p>
</form>
</div>
</html>

Assign controller to element dynamically after bootstrap

I have an AngularJS app that I manually bootstrap at time 't'. At time 't + 1', I would like to show an HTML element that has no ng-controller attached. I would like to dynamically add a ng-controller to this element so it can communicate with my javascript code.
How can I do that?
PS I tried to dynamically add the ng-controller attribute to the element but it doesn't work.
To do that you need to compile elements.
HTML
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.5/angular.min.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="main.css" rel="stylesheet" type="text/css" />
<script src="main.js"></script>
<meta charset=utf-8 />
<title>Angular JS</title>
</head>
<body ng-controller="parentCtrl">
<button ng-click="setCtrl2()">Set Controller</button>
<div id="placeholder">
<span></span>
<select>
<option></option>
</select>
<span class="input-append">
<input id="add" type="text" placeholder="Another one ?" ng-model="addName" />
<input type="submit" class="btn btn-primary" ng-click="addRow()" value="+ add" />
</span>
</div>
</body>
</html>
Javascript
angular.module('app', []);
angular.module('app').controller('ctrl', function($scope) {
$scope.rows = ['Paul','John','Lucie'];
$scope.name = 'Jack';
$scope.addRow = function(){
$scope.rows.push($scope.addName);
$scope.addName = "";
console.log($scope.rows);
};
})
.controller('parentCtrl', function($scope) {
$scope.setCtrl2 = setCtrl;
});
function setCtrl() {
var elem = document.getElementById('placeholder');
elem.setAttribute('ng-controller', 'ctrl');
var eSpan = elem.children[0];
var eSelect = elem.children[1].children[0];
eSpan.setAttribute('ng-bind', 'name');
eSelect.setAttribute('ng-repeat', 'row in rows');
eSelect.setAttribute('value', '{{ row }}');
eSelect.setAttribute('ng-bind', 'row');
var injector = angular.element(elem).injector();
var compile = injector.get('$compile');
var rootScope = injector.get('$rootScope');
var result = compile(elem)(rootScope);
// When outside of AngularJS you need to call digest
// rootScope.$digest();
}
See: http://codepen.io/skarllot/pen/LVKpgd
You don't mention whether you've looked at previously asked questions. I found two which look like they could address the question you've asked:
Loading an AngularJS controller dynamically
How to bind an AngularJS controller to dynamically added HTML?

Angular: when using ng-include, number variable become NaN [duplicate]

This question already has answers here:
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
(3 answers)
Closed 7 years ago.
I have a problem when i try to fragment my html with ng-include:
This is what my index.html page looks like when it works (prix=price, TVA=tax):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link type="text/css" rel="stylesheet" href="style.css" />
<title> TVA </title>
</head>
<body>
<div>
<div ng-app="app" ng-controller="appCtrl">
<input ng-model="tva" placeholder="TVA" /><br />
<input ng-model="prix" placeholder="Prix" />
<select ng-model="taxe">
<option>HT</option>
<option>TTC</option>
</select>
<button id="btn" ng-click="calcul()">Calculer</button>
<p>{{ total }}</p>
</div>
</div>
<script src="angular.min.js"></script>
<script src="script.js"></script>
</body>
</html>
The script.js :
app = angular.module('app', []);
app.controller('appCtrl', ['$scope', function ($scope) {
$scope.calcul = function() {
if ($scope.taxe == "TTC") {
$scope.total = parseInt($scope.prix) + $scope.prix * $scope.tva /100;
} else if($scope.taxe == "HT") {
$scope.total = 1/(1+$scope.tva/100)*$scope.prix;
}
};
}]);
So this works, the result is an number (the price with or without tax).
When I use the ng-include like this:
<div>
<div ng-app="app" ng-controller="appCtrl">
<div ng-include="'tva.html'"></div>
<input ng-model="prix" placeholder="Prix" />
<select ng-model="taxe">
<option>HT</option>
<option>TTC</option>
</select>
<button id="btn" ng-click="calcul()">Calculer</button>
<p>{{ total }}</p>
</div>
</div>
I only tried to replace the first input with a new HTML page.
The tva.html :
<input ng-model="tva" placeholder="TVA" /><br />
Now the results show "NaN" (I put those codes on a server so that I can check online). Why is this?
#Josh Beam Answered & explained ng-include creates a child scope on creating the DOM. I'd suggest you to use dot rule in angular that will follow prototypal inheritance on that object and you object value will access in child scope.
Now your object structure will changed to $scope.model={}; and this model will have all the input values. like all will become like model.prix, model.taxe & model.tva so that the prototypal inheritance will follow.
Markup
<div ng-app="app" ng-controller="appCtrl">
<div ng-include="'tva.html'"></div>
<br />
<input ng-model="model.prix" placeholder="Prix" />
<select ng-model="model.taxe">
<option>HT</option>
<option>TTC</option>
</select>
<button id="btn" ng-click="calcul()">Calculer</button>
<p>{{ total }}</p>
</div>
Code
app.controller('appCtrl', ['$scope', function ($scope) {
$scope.model = {};
$scope.calcul = function() {
if ($scope.model.taxe == "TTC") {
$scope.total = parseInt($scope.model.prix) + $scope.model.prix * $scope.model.tva /100;
} else if($scope.model.taxe == "HT") {
$scope.total = 1/(1+$scope.model.tva/100)*$scope.model.prix;
}
};
}]);
tva.html
<input ng-model="model.tva" placeholder="TVA" /><br />
Demo Plunkr
Short answer: don't use ng-include in this instance.
Long answer: ng-include creates a new child scope, so ng-model inside the ng-include isn't appCtrl's TVA. I don't see a reason here to use ng-include anyway, your code is fine without it.
So basically you're getting NaN (not a number) because $scope.TVA is never set when using the ng-include... you're attempting to multiply an undefined variable by another number, which returns NaN:
The reason for that is the ng-include creates a new scope under the scope when the HTML was included, but you can access to the parent scope by specifying $parent
<input ng-model="$parent.tva" placeholder="TVA" /><br />
A better approach is give an alias to your controller, so it will be clear semantically to children controllers accessing to a specific parent.
<div ng-app="app" ng-controller="appCtrl as vmMain">
<div ng-include="'tva.html'"></div>
... and in the other file:
<input ng-model="vmMain.tva" placeholder="TVA" /><br />

Trigger AngularJS $scope event on key press [duplicate]

This question already has answers here:
How to use a keypress event in AngularJS?
(19 answers)
Closed 7 years ago.
Is it possible to trigger a $scope function on keypress. I like to know whats the most comfortable way to handle key press in a "form case". I created a dummy plunker.
Controller
// Code goes here
var myApp = angular.module("myApp", []);
//main controller define
myApp.controller('MainCtrl', ['$scope', MainCtrl]);
/**
* MainCtrl object wrapper
*/
function MainCtrl ($scope) {
/**
* Submit function
*/
$scope.submit = function () {
console.log('Submit was triggered');
}
}
View
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.3.15" data-semver="1.3.15" src="https://code.angularjs.org/1.3.15/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="MainCtrl">
<input type="text" placeholder="Trigger on enter key" />
<button ng-click="submit();">Trigger on click</button>
</div>
</body>
</html>
Try wrapping it in a form tag and using ng-submit
<form ng-submit="submit()">
<input type="text" placeholder="Trigger on enter key" />
<button>Trigger on click</button>
</form>

Categories