Why is safari not rendering my AngularJS bindings properly? - angularjs

I've encountered an angular issue that only seems to occur in Safari:
TL;DR - Here is an obvious example of what I describe below (obviously this will only be demonstrated if you run the plunk in safari)
https://plnkr.co/edit/t6Ts2DlhV84C7CLFzdui?p=preview
<html>
<head>
<script src="https://code.angularjs.org/1.6.6/angular.js"></script>
<script>
var app = angular.module('safariBug', []);
app.controller('main', function($scope) {
$scope.mytext = "Here is a bunch of text, some of which will continue to be displayed.";
$scope.update = function() {
$scope.mytext = "New line of text.";
}
});
</script>
</head>
<body ng-app='safariBug'>
<div ng-controller='main'>
<div style='height:300px;width:300px;font-size:48px'>{{mytext}}</div>
<input type='button' ng-click='update()' value='Update Text' />
</div>
</body>
</html>
When displaying a string in a view using a data-bound variable, replace the string with a new value it gets displayed immediately, but if the old value is longer it doesn't get erased. For instance if the string is "An original sentence", and its replaced with "New text", it will end up displaying something such as "New textinal sentence". As soon as the the style of the html element is modified, it seems to force Safari to re-render the element correctly with the old text removed.

<div style='height:300px;width:300px;font-size:48px' ng-bind="mytext"</div>
Try this way.

Related

Why are my angular curly braces not working?

My curly braces are showing up as curly braces, I don't get what's wrong, I did everything...when I use the controller to manipulate the input box, it works. But when I sumbit text into the input box on my browser, it doesn't do anything..
This is where I create my module:
'use strict';
var foodApp=angular.module('foodApp', []);
This is my html:
<script src="/lib/angular/angular.js"></script>
<!DOCTYPE html>
<html lang="en-us" >
<head>
<meta charset="utf-8">
<title>Food App</title>
</head>
<body>
<div ng-controller="foodController" ng-app="foodApp">
<input type="text" ng-model="foods"/>
<input type="submit" value="Healthy Lunch?" />
<br />
<br />
<h4>{{outcome}}</h4>
{{foods}}
</div>
<script src="/js/food.js"></script>
<script src="/js/controllers/foodController.js"></script>
</body>
</html>
This is my controller page:
foodApp.controller('foodController', function($scope)
{
var foods = $scope.foods;
$scope.outcome=foods;
var foodsArray=foods.split(',');
if(foodsArray.length<=4)
$scope.outcome="Bon Appetit!";
else if(foodsArray.length<=7)
$scope.outcome="Pig!";
else
$scope.outcome="One at a time, your scale is going to shout!!";
});
The problem is in fact in your controller. The code you have in your controller is only executed once, when the controller is constructed. As such the variable foods is undefined (since $scope.foods is also undefined). A couple of lines later, you try to run foods.split(..) but since it's undefined, it throws an exception and the application fails. This is shown as an error in the developer console of your browser.
To fix it you need to completely refactor your controller code.
foodApp.controller('foodController', function($scope)
{
$scope.handleFoodChange = function() {
$scope.outcome = $scope.foods;
if($scope.foods){
var foodsArray = $scope.foods.split(',');
if(foodsArray.length<=4)
$scope.outcome = "Bon Appetit!";
else if(foodsArray.length<=7)
$scope.outcome = "Pig!";
else
$scope.outcome = "One at a time, your scale is going to shout!!";
}
}
});
and in your view you should change your input to this:
<input type="text" ng-model="foods" ng-change="handleFoodChange()" />
That should make your application work as expected. Now, whenever you make a change in the input field, the function handleFoodChange is called, and it handles the logic that sets a value for the $scope.outcome variable.
Here's a Plunker showing it working

Access form inside controller

Here is my full code:
<html ng-app="myApp">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.js"></script>
</head>
<body >
<div ng-controller="myController">
<form name="myForm">
<input ng-model="option" name="test">
{{myForm.$dirty}}
<button>Save</button>
</form>
</div>
<script>
angular.module('myApp',[]).controller('myController',function($scope){
$scope.option=2;
console.log($scope.myForm);
});
</script>
</body>
</html>
While {{myForm.$dirty}} works, console.log($scope.myForm) returns undefined!!! At the same time if I console.log($scope) I can see myForm as one of its properties!!!! As not to go mad, could someone explain this paradox?
I don't like this solution, but it works. Put a $timeout around the code that you would like to access the form. The $timeout kind of forces the code to wait until the form is fully rendered. (Don't forget to inject $timeout.)
angular.module('myApp',[]).controller('myController',function($scope, $timeout){
$scope.option=2;
$timeout(function() {
console.log($scope.myForm);
}); //Note that you don't need it to actually wait for any amount of time
The reason why you see the form if you console.log($scope) but not when you console.log($scope.myForm), is because the console will evaluate $scope when you expand it. By then, the form has rendered and attached to the scope.
Have you tried to put a watcher on the form ? I'm guessing that the form is simply not yet defined when the controller code is defined.
$scope.$watch('myForm', function(form) {
if(form) {
//check if form is defined
}
});

How to parse multiple variables via ng-click into a angularjs function

I'm new to angularJS and can't seem to figure out how to parse multiple variables from a html button thru an angular JS function.
<html ng-app="">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
</head>
<body ng-controller='CartController'>
<script>
function CartController($scope) {
$scope.addToCart = function(index,product) {
alert(product);
};
}
</script>
<button ng-click="addToCart(2,iPhone);">Add to cart</button>
</body>
</html>
I would expect the second variable (iPhone) would get stored in variable named product but the alert shows its undefined.
What am I doing wrong?
Try using ng-click="addToCart(2,'iPhone');"
What you want is to pass the string 'iPhone', not a property on the $scope called iPhone.
Without the quotes, it will be evaluated against the $scope in CartController. There is no iPhone property on $scope so it will be undefined.
Your original try would work if in CartController you'd have:
$scope.iPhone = "Hello";
The string Hello would be passed to the addToCart function.

Angular Dropdown (could be just IE): strange positioning of dropdown in IE

I'm taking baby steps with Angular and writing simple stuff and testing across browsers, I have a simple script to bind a menu against a JSON string array. I want to do the whole Angular MVC instead of Javascript DOM manipulation.
In my tests I can see a strange behaviour as to the positioning of the top of the menu in IE dependent upon which item is selected. Anyone know how to fix this? I would like to use an Angular friendly solution, like Bootstrap?
Menu looks good in Firefox and Chrome.
<html ng-app="myNoteApp">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<body>
<div ng-controller="myCarSelector">
<h2>Menu</h2>
<p>Make of car : <span ng-bind="selectedCarMake"></span></p>
<select ng-model="selectedCarMake" ng-options="val for val in carmakes"></select>
</div>
<script>
// was in separate file but pasted in for demo purposes
var app = angular.module("myNoteApp", []);
</script>
<script>
// was in separate file but pasted in for demo purposes
app.controller("myCarSelector", function ($scope) {
$scope.selectedCarMake = "BMW"; // default value
$scope.carmakes = ["Audi", "BMW", "Volkswagen"];
});
</script>
</body>
</html>
I like to accept answers and then move on to next question.
Here is a screen grab of the problem in IE 11
It seems browser default behaviour.

Angularjs controller nesting

I'm new to angular, I've tried some testing pattern and it's ok with the $scope variable but I can't make it work for a simple controller nesting. (and avoid using the $scope variable, instead I want to use "this")
Here is my sample HTML and javascript :
<!doctype html>
<html ng-app="appTest">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
</head>
<body>
<div ng-controller="FirstController as first">
<div>
First is {{first.text}}
</div>
<div ng-controller="SecondController as second">
Second is {{second.text}}
</div>
</div>
<script>
var app = angular.module("appTest",[]);
function printFirst() {
this.text = "first"
}
function printSecond() {
this.text = "second";
}
app.controller("FirstController",[printFirst]);
app.controller("SecondController",[printSecond]);
</script>
</body>
</html>
In the output html the angular variables inside curly brackets are not replaced and I don't know what's going on. I've tried to install Angular Batarang for debugging but the scope console is empty.
Obviously it's a silly mistake but I don't see where I'm wrong
Ok, the answer has nothing to do with my code, I was just using a too old version of Angularjs (1.0.8).
I moved to the last version 1.3.4 and it works fine.
Access the variable using $scope.text please instead of this.text.

Resources