Angular ng-if + function not work - angularjs

In this first code when I change the anoini, the gerar() function show the old value.
But, when I remove <div ng-if.... works fine.
do you knows what's wrong ?
Tks
// JavaScript Document
var app = angular.module('dadosHist', []);
app.controller('dadosHistCtrl', function($scope) {
$scope.mesini = 1; $scope.anoini = 2011;
$scope.mesfim = 7; $scope.anofim = 2015;
$scope.log = "";
$scope.escolherperiodo = true;
$scope.gerar = function() {
this.log = this.anoini;
meses = ((this.anofim - this.anoini) * 12) + (12 - this.mesini) + this.mesfim;
qtdLoop = arrEstacoes.length * meses;
tempoEstimadoMinutos = Math.round((qtdLoop * 20) / 60 );
this.log = 'Tempo Estimado: ' + tempoEstimadoMinutos + ' min.' ;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="dadosHist" ng-controller="dadosHistCtrl">
<input type="checkbox" ng-model="escolherperiodo">Escolher PerĂ­odo<br>
<div ng-if="escolherperiodo">
<input type="text" ng-model="mesini" placeholder="Mes">/<input type="text" ng-model="anoini" placeholder="Ano"><br>
<input type="text" ng-model="mesfim" placeholder="Mes">/<input type="text" ng-model="anofim" placeholder="Ano"><br>
</div>
<button ng-click="gerar()">Gerar</button> <br>
{{log}}
</div>

Always use a dot in ng-model ! . In other words use objects not primitives.
ng-if creates a child scope and since you are using primitives in ng-model you are losing 2 way binding with scope from this child scope.
var myModel ={
mesini : 1,
anoini : 2011,
mesfim : 7,
anofim : 2015
};
$scope.myModel = myModel;
HTML
<input type="text" ng-model="myModel.mesini">
Then in function:
$scope.gerar = function() {
$scope.log = myModel.anoini;
var meses = ((myModel.anofim - myModel.anoini)......
.....
}
Understanding scope nesting in angular is the most important thing to learn when using the framework

You should not assign value to this, but to $scope inside gerar function:
$scope.gerar = function() {
$scope.log = $scope.anoini;
meses = (($scope.anofim - $scope.anoini) * 12) + (12 - $scope.mesini) + $scope.mesfim;
qtdLoop = arrEstacoes.length * meses;
tempoEstimadoMinutos = Math.round((qtdLoop * 20) / 60 );
$scope.log = 'Tempo Estimado: ' + tempoEstimadoMinutos + ' min.' ;
}

Related

Using for loop in angular with $scopes

Is it possible to made a for loop using scopes in angular? For example. I have:
$scope.start = 1;
$scope.end = 10;
and want to make a for (example i know it doesn't work)
for($scope.start; $scope.start < $scope.end; $scope.start++) {
print(<input type="radio" name="count" value="$scope.start">);
}
angular.module('app', []).controller('MyController', ['$scope', function($scope) {
$scope.start = '8:00';
$scope.stop = '20:00';
$scope.interval = '30';
$scope.getTimeArray = function(start, stop, interval){
var result = [];
if(interval == '0')
return result;
function toMinutes(time){
var pair = time.split(':');
return pair[0] * 60 + 1 * pair[1];
}
function toString(minutes){
var hours = Math.floor(minutes / 60);
var min = (minutes - hours * 60);
min = min > 9 ? min : '0' + min;
return hours + ':' + min;
}
for(var i = toMinutes(start); i <= toMinutes(stop); i += 1 * interval)
result.push(toString(i))
return result;
}
}])
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<div ng-app='app' ng-controller="MyController">
start: <input type="text" ng-model='start'>
</br>
stop: <input type="text" ng-model='stop'>
</br>
interval: <input type="text" ng-model='interval'>
</br>
<label ng-repeat-start='item in getTimeArray(start, stop, interval)'>{{item}}</label>
<input type="radio" name="count" value="{{item}}" ng-repeat-end>
</div>

Change Different type of Attributes for Dynamically added every element

How can I Change (type) Attribute for each added dynamic buttons? In below code, label names were changing perfectly, but when i am trying to change button types it is applying to all added dynamic buttons,
My requirement is have to change every button type with different types (means: first added button type to submit, second added type to reset, third added button to cancel). but in my code if i change second button type to 'Reset' at the same time the first button type also going to Reset type... can u please tell me how can i change button type for every added element ...
Working DEMO
Updated:
var app = angular.module('myapp', ['ngSanitize']);
app.controller('MainCtrl', function($scope, $compile) {
var counter = 0;
$scope.buttonFields = [];
$scope.add_Button = function(index) {
$scope.buttonFields[counter] = {button: 'Submit'};
var buttonhtml = '<div ng-click="selectButton(buttonFields[\'' + counter + '\'])"><button id="button_Type">{{buttonFields[' + counter + '].button}}</button>//click//</div>';
var button = $compile(buttonhtml)($scope);
angular.element(document.getElementById('add')).append(button);
$scope.changeTosubmit = function (val) {
$scope.buttonField = val;
var els = document.body.querySelectorAll('#button_Type');
for (var i = 0, ils = els.length; i < ils; i++) {
var el = els[i];
el.setAttribute("type", "submit");
compile(el);
}
};
$scope.changeToreset = function (val) {
$scope.buttonField = val;
var els = document.body.querySelectorAll('#button_Type');
for (var i = 0, ils = els.length; i < ils; i++) {
var el = els[i];
el.setAttribute("type", "reset");
compile(el);
}
};
$scope.changeTocancel = function (val) {
$scope.buttonField = val;
var els = document.body.querySelectorAll('#button_Type');
for (var i = 0, ils = els.length; i < ils; i++) {
var el = els[i];
el.setAttribute("type", "cancel");
compile(el);
}
};
++counter;
};
$scope.selectButton = function (val) {
$scope.buttonField = val;
$scope.showButton_Types = true;
};
});
function compile(element) {
var el = angular.element(element);
$scope = el.scope();
$injector = el.injector();
$injector.invoke(function ($compile) {
$compile(el)($scope);
});
};
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<script src="https://code.angularjs.org/1.4.8/angular.js"></script>
<script src="https://code.angularjs.org/1.5.0-rc.0/angular-sanitize.min.js"></script>
</head>
<body ng-controller="MainCtrl">
<button ng-click="add_Button($index)">Add Buttons</button>
<hr>
<div id="add"></div>
<form ng-show="showButton_Types">
<div>
<label>Button Name(?)</label><br/>
<input ng-model="buttonField.button">
</div>
<div>
<label>change button types(?)</label><br/>
<input ng-click="changeTosubmit(buttonFields['' + counter + ''])" name="submit" type="radio"> Submit
<input ng-click="changeToreset(buttonFields['' + counter + ''])" name="submit" type="radio"> Reset
<input ng-click="changeTocancel(buttonFields['' + counter + ''])" name="submit" type="radio"> Cancel
</div>
</form>
</body>
</html>

Change listeners on 2 directives should produce one action on another directive

I'm struggeling with this problem for too long, need some help.
I made a snippet so the problem is easier to understand.
The purpose: make the DURATION input readOnly, when FROM AND TO are != null
The problem remains in how directives communicate together.
I think code is better than text explanation...
(function(){
angular.module('app', [])
.controller('AppController', function($scope){
$scope.from = 3600;
$scope.to = 7200;
$scope.duration = "null";
})
.directive('hourInput', function(){
return {
restrict : 'A',
require : 'ngModel',
link : function(scope, element, attrs, modelCtrl){
//Change scope copy of view
modelCtrl.$formatters.push(function(seconds){
if(seconds == "null" || seconds == null){
return "";
}
var sec_num = parseInt(seconds, 10);
var hours = Math.floor(sec_num / 3600);
var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
hours = (hours < 10) ? "0" + hours : hours;
minutes = (minutes < 10) ? "0" + minutes : minutes;
//Only hours matters
return hours + ":" + minutes;
});
//Change scope copy of model
modelCtrl.$parsers.push(function(time) {
if(time.length != 5){
return "null";
}
var hours = parseInt(time.substring(0, 2));
var minutes = parseInt(time.substring(3));
return ((hours * 60) + minutes) * 60 + "";
});
//The problem is here
/*
Goal : set duration on readOnly when from || to == "null"
Problem :
This can't happen here, because can't watch both inputs.
Solution:
- Create 2 directives? (1 in each input : from and to)
- COntroller?
- ...
NOte : I know I can watch on changes with :
modelCtrl.$viewChanheListener... but the problem is:
if FROM == null -> duration will ne readOnly even if TO != null
*/
}
};
});
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="app" ng-controller="AppController">
<input type="text" ng-model="from" placeholder="from" hour-input/> <br />
<input type="text" ng-model="to" placeholder="to" hour-input/> <br />
<input type="text" ng-model="duration" placeholder="duration" get-duration/> <br />
{{from}}
</div>

how to add timeout to ng-show in angular js?

I am working on quiz app. I have add the time out to every question even though user attempts the question or not.
my code in view:
<p ng-repeat="opt in question.answer">
<label ng-show="opt._correct" for="">
<input type="radio" name="questionAnswer" id="opt.id" value=""
ng-click="checkAnswer(1)" />
{{opt.__text}}
</label>
<label ng-hide="opt._correct" for="">
<input type="radio" name="questionAnswer" id="opt.id" value=""
ng-click="checkAnswer(0)" />
{{opt}}
</label>
</p>
my code in controller:
$scope.randomQuestions = function(questionslist){
$scope.randomQuestion = questionslist
[Math.floor(Math.random() * questionslist.
length)];
console.log($scope.quiz);
var item = $scope.quiz.splice($scope.randomQuestion,1)[0];
$scope.questions = new Array();
$scope.questions.push($scope.randomQuestion);
$scope.counter = $scope.counter + 1;
return $scope.questions;
}
$scope.checkAnswer = function(option){
console.log('check answer');
if(option == 1){
console.log($scope.score);
$scope.score = $scope.score + parseInt($scope.level._points_per_question);
console.log($scope.score);
} else{
}
console.log($scope.counter);
if ($scope.counter < parseInt($scope.level._total_questions + 1)){
$scope.randomQuestions($scope.quiz);
} else {
console.log('5 questions');
}
}
$scope.nextLevel = function(){
$scope.total_score = $scope.total_score + $scope.score;
$scope.score = 0;
$scope.counter = 0;
if($scope.level_count == 1){
$scope.level_count = $scope.level_count + 1;
$scope.quiz = $scope.quiz2.question;
$scope.level = $scope.quiz2;
$scope.randomQuestions($scope.quiz);
} else if($scope.level_count == 2){
$scope.quiz = $scope.quiz3.question;
$scope.level = $scope.quiz3;
$scope.randomQuestions($scope.quiz);
$scope.level_count = $scope.level_count + 1;
} else {
$scope.level_count = $scope.level_count + 1;
$scope.result_text();
}
}
$scope.result_text = function(){
$scope.result = parseInt(($scope.total_score * 100) / 400);
for(var k=0; k < $scope.score_rules.length; k++){
if($scope.result >= $scope.score_rules[k]._min_percent){
$scope.score_status = $scope.score_rules[k].__text;
console.log($scope.score_rules[k].__text);
console.log($scope.score_rules[k]);
}
}
}
Can any one suggest how to call time out from view?
Please find below the code
function controller($scope)
{
$scope.showflag = true;
setTimeout(function ()
{
$scope.$apply(function()
{
$scope.showflag = false;
});
}, 1000);
}
You could use CSS transitions or animation to do the actual transition and use ngAnimate to trigger the transitions.
There are a few examples for ngAnimate on this page.
You can try this approach:
Modify your checkAnswer() code and call another function which sets
the timeout/sleep. When the call returns from the timeout function, set a
variable (eg. isVisible) to false and use this variable in ng-show.
Something like this:
So, new ng-show would look like ng-show=" isVisible && opt._correct"

Shared Variables between Controllers with a Service in AngularJS

I'm trying to share a group of variables between my controllers, but it does not seem to be working, I already followed some example but can't make it to work.
Below is the JavaScript
angular.module('PickMeUp.controllers', []).
service('sharedProperties', function() {
// Car Variables
var make;
var model;
var color;
// Bldg Variables
var building = 'b';
var door = 'd';
return {
getCar: function () {
return make + " " + model + " " + color;
},
getBldg: function () {
return building;
},
getDoor: function () {
return door;
},
setCar: function (make1, model1, car1) {
make = make1;
model = model1;
car = car1;
},
setBldg: function (building1, door1) {
building = building1;
door = door1;
//****When this is called, displays the new values****
alert("Bldg " + building);
alert("Door " + door);
}
};
}
})
.controller('MyCtrl2', ['$scope', 'sharedProperties', function ($scope, sharedProperties) {
$scope.sharedProperties = sharedProperties
console.log("ctrl2");
$scope.passenger = 'esau';
$scope.building = sharedProperties.getBldg();
$scope.door = sharedProperties.getDoor();
//****This is giving me the default values****
console.log($scope.building);
console.log($scope.door);
//****This is undefined****
alert("Bldg " + sharedProperties.building);
alert("Door " + sharedProperties.door);
} ])
.controller('BuildingChgCtrl', ['$scope', 'sharedProperties', function ($scope, sharedProperties) {
$scope.sharedProperties = sharedProperties;
$scope.buildings = ['DGTC', 'Walmart Home Office', 'Sam\'s Home Office'];
$scope.exits = ['East', 'West', 'Vendor'];
$scope.building;
$scope.door;
$scope.exitDisplay = 'none';
$scope.change = function () {
$scope.exitDisplay = 'inline';
console.log("changed display");
};
console.log("controller called ");
//$scope.building = sharedProperties.getBldg();
//$scope.door = sharedProperties.getDoor();
console.log($scope.building);
console.log($scope.door);
// $scope.setBldg = function(b,d) {
// alert("Bldg " + sharedProperties.building);
// alert("Door " + sharedProperties.door);
//
// sharedProperties.building = b;
// sharedProperties.door = d;
// //****When this is called, displays the new values****
// alert("Bldg " + sharedProperties.building);
// alert("Door " + sharedProperties.door);
// }
} ]);
And below the HTML
building.html
<form action="{{nextURL}}">
<div ng-controller="BuildingChgCtrl">
<select ng-change="change()" ng-model="$parent.building" ng-options="b for b in buildings">
<option value="" style="display:none;">Choose building</option>
</select>
<br />
<select style="display:{{exitDisplay}};" ng-model="$parent.door" ng-options="e for e in exits">
<option value="" style="display:none;">Choose Exit</option>
</select>
<br />
bldg1 = {{building}}, door1 = {{door}} <br />
<button ng-click="sharedProperties.setBldg(building,door)">Next</button>
Next
</div>
<br />
bldg2 = {{building}}, door2 = {{door}}
</form>
passenger.html
<div>Passenger 1</div>
{{passenger}} <br />
building = {{sharedProperties.building}}<br />
door = {{sharedProperties.door}}</div>
index.html at least the important code on this page
...
<div ng-view>
</div>
....
app.js at least the important code
$routeProvider.when('/building', {templateUrl: 'partials/Building.html', controller: 'DriverBuildingCtrl'});
$routeProvider.when('/passengerQueue', {templateUrl: 'partials/Passenger.html', controller: 'MyCtrl2'});
This is how is supposed to work. In building.html I am setting the building (a drop down) when I click on Next button, and I want to display it in passenger.html
Thanks
<button ng-click="setBldg(building,door)">Next</button> is probably throwing an error ( check your browser debug console and let me know if it is the case)
ng-click is trying to call BuildingChgCtrl.setBldg, which doesnt exist in the code you have shown.
if you add the following to your BuildingChgCtrl
$scope.sharedProperties = sharedProperties
and change the ng-click to
<button ng-click="sharedProperties.setBldg(building,door)">Next</button>
that should be a step in the right direction.
Further to that, you will be able to reduce the code if you also add $scope.sharedProperties = sharedProperties to MyCtrl2 and bind with {{sharedProperties.door}}

Resources