How to update a Model after Reading Data from JSON in AngularJS - javascript

I'm trying to write an App in AngularJS and at some point I update my Data via a Form:
<h3> Anzeige </h3>
<form name="anzeige-form" ng-controller="AnzeigeController as anzCtrl" ng-submit="anzCtrl.getMyOrder()">
<label for="id">Meine Bestellnummer</label><input type="text" required class="form-control" id="id" ng-model="anzCtrl.id" placeholder="0..X" />
<button type="submit" class="btn btn-default">Laden / Aktualisieren</button>
<div class="ausgabe">
Ihre Adresse : {{anzCtrl.myorder.order.address}}
<ul class="list-unstyled anzeige">
<li class="list-item" ng-repeat="pizza in anzCtrl.myorder.order.cart">
<h3>{{pizza.name}}</h3><br/>
<span class="status" ng-if="pizza.status=0">Bestellt</span>
<span class="status" ng-if="pizza.status=1">Im Ofen</span>
<span class="status" ng-if="pizza.status=2">Lieferbereit</span>
<span class="status" ng-if="pizza.status=3">Unterwegs</span>
<span class="status" ng-if="pizza.status=4">Lieferbereit</span>
<div class="progress">
<div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="{{pizza.status}}" aria-valuemin="0" aria-valuemax="4" style="width: {{pizza.status * 25}}%">
<span class="sr-only">{{pizza.status * 25}}% Abgeschlossen</span>
</div>
</div>
</li>
</ul>
</div>
</form>
The Angular Code looks like this:
.controller('AnzeigeController',function($http){
//$scope.adress = '';
this.id = 21;
//this.myorder = order2;
this.myorder = {};
//$scope.myarray = {};
this.getMyOrder = function(){
$http.get('get_by_id.php',{params:{"id": this.id}}).success(function(datar){
this.myorder = angular.fromJson(datar);
console.log(this.myorder);
})
}
})
My Problem is now, I don't know how to tell Angular that an asynchronous update has occured and my List will Update with the right values. Logging the myorder variable gives me a correct Object in the debugger / console.
I mostly don't understand how to access the data, because the Line {{anzCtrl.myorder.order.address}} doesn't show anything.
I have a major thinking error is my guess.
Pls clarify how to do it correctly.
Best Regards, Marc

The problem is that this no longer refers to the controller model when your promise resolves. You need to create another variable to hold this and then use this other variable when your promise resolves.
.controller('AnzeigeController', function($http) {
var _this = this;
_this.id = 21;
_this.myorder = {};
_this.getMyOrder = function() {
$http.get('get_by_id.php',{params:{"id": _this.id}}).success(function(datar){
_this.myorder = angular.fromJson(datar);
console.log(_this.myorder);
})
}
})

Related

Calling JavaScript function as parameter in #Url.Action

So I am trying to return a value from a text box as the parameter to another controller action that returns another partial. I think it would easier to just post some sample code rather than trying to explain what I am trying to do, so here is some sample code:
CSHTML:
<div class="row">
<div class="pt-sm-30 pb-xs-30 has-50px-footer">
<div class="col-lg-offset-1 col-lg-10">
<h3>CREATE A NEW PERSON PROFILE</h3>
<form class="form-spacers">
<div class="form-group">
<div class="row">
<div class="col-md-6">
<label class="input-label" for="functionalRole">First Name <span class="ReqField">*</span></label>
#Html.TextBoxFor(model => model.Person.FirstName, new { #class = "form-control input-sm", #id = "firstName", #type = "text" })
</div>
<div class="col-md-6">
<label class="input-label" for="functionalRole">Last Name <span class="ReqField">*</span></label>
#Html.TextBoxFor(model => model.Person.LastName, new { #class = "form-control input-sm", #id = "lastName", #type = "text" })
</div>
</div>
</div>
</form>
</div>
</div>
<div class="row">
<div class="col-sm-8 col-md-9 col-lg-10 new-profile-footer">
<div class="col-lg-offset-1 col-lg-5 col-md-4 hidden-sm hidden-xs" style="margin-top: 16px;">
</div>
<div class="col-lg-6 col-md-8 col-sm-12" style="margin-top: 10px; text-align: right;">
<div class="row" style="white-space: nowrap;">
<button class="btn btn-primary button-blue btn-xs-110" onclick="location.href='#Url.Action("Index", "DirectoryMaintainer")'"><i class="fa fa-times-circle-o icon-xs-hidden" aria-hidden="true" style="padding-right: 5px;"></i>CANCEL</button>
<button id="continue" type="button" class="btn btn-success button-green btn-xs-110">CONTINUE<i class="fa fa-caret-right icon-xs-hidden" style="padding-left: 5px;" aria-hidden="true"></i></button>
</div>
</div>
</div>
</div>
<script>
$("#continue").click(function () {
$("#partialViewDiv").load('#(Url.Action("RecordsMatch", "DirectoryMaintainer", new { #firstName = getFirstName(), #lastName = getLastName()}, Request.Url.Scheme))');
});
function getFirstName() {
return document.getElementById("firstName").value;
}
function getLastName() {
return document.getElementById("lastName").value;
}
</script>
Controller:
public PartialViewResult RecordsMatch(string firstName, string lastName)
{
//Do some logic with parameters here
return PartialView("_RecordsMatch");
}
So the issue I am having this that the line
$("#partialViewDiv").load('#(Url.Action("RecordsMatch", "DirectoryMaintainer", new { #firstName = getFirstName(), #lastName = getLastName()}, Request.Url.Scheme))');
is giving me an error on getFirstName() and getLastName(). The error is "The name getFirstName() does not exist in the current context". I am pretty new to MVC so I'm not sure if this is even possible or if there is a better way of doing it. If there is, then I am more than happy to learn it. Any and all suggestions would be greatly appreciated.
You cannot mix c# and js like that as the Url.Action gets executed in the server before your js code
Basically any C# code in your razor view gets executed by the razor view engine in the server and output of that (which is HTML/plain text) will be send to the browser. All your javascript code gets executed in the browser.
You can use Url.Action to generate the base url (without route value parameters) and add query strings to that at client side later.
$(function(){
$("#continue").click(function () {
var url='#Url.Action("RecordsMatch", "DirectoryMaintainer")';
url = url+'?firstName='+ getFirstName()+'&lastName='+getLastName();
$("#partialViewDiv").load(url);
});
});
When razor executes this code, it will render output like this (you can check the page view source and see this)
$(function(){
$("#continue").click(function () {
var url='/DirectoryMaintainer/RecordsMatch';
url = url+'?firstName='+ getFirstName()+'&lastName='+getLastName();
$("#partialViewDiv").load(url);
});
});

Ng model with no parameters in the controller

I have a filter that when i'm passing in the controller it comes undifined.
This is my template.
<div class="row">
<div ng-show="filtroReduzido" class="col-md-2">
<div class="form-group">
<label>Codigo Reduzido</label>
<div class="form-group form-md-line-input no-hint right" style="padding-top: 3px;">
<select id="reduzido" name="reduzido" chosen width="150" allow-single-deselect="true" ng-model="vm.filtro.numero_contrato" style="width:100%"
ng-options="clienteFiltro as cliente.Numero_Contrato for cliente in vm.importacaoSiltDet |unique:'Numero_Contrato'| orderBy:'Numero_Contrato'"></select>
</div>
</div>
</div>
</div>
IN the controller i'm using.
vm.filtro = {};
and in the function i'm using this but in test if comes undifined, i think it was supose to work in the vm.filtro.numero_contrato, someone knows what is causing this?
vm.filtrarDetFiltrado = function () {
debugger;
var dateDe = formatarData(vm.relatorio.dataDe);
var dateAte = formatarData(vm.relatorio.dataAte);
var test = vm.filtro.numero_contrato;

Retrieving array list one by one from local storage

I am creating a sample todo application in which I can add/remove tasks but when I refresh the page, data is lost. So I decided to use localStorage to save the task lists and retrieve it when page refreshes.
I am able to do the same but I can retrieve the data only as a array list. How can i list tasks one by one stored in my localStorage and display it exactly like how it was before page load?
HTML CODE
<body ng-app="todoApp">
<div ng-controller="addTaskController" data-ng-init="init()">
<div class="container">
<h3>ToDo Application</h3>
<div class="form-group col-md-6">
<form ng-submit="addTask()" class="form-inline">
<input type="text" placeholder="Enter Your Task" ng-model="newTask" class="form-control">
<button type="submit" class="btn btn-primary">Add Task</button>
<div class="taskList">
<ol>
<li ng-repeat="task in tasks track by $index">{{task}} <i style="color:red;margin-left:10px;cursor:pointer;" class="fa fa-times" aria-hidden="true" ng-click="deleteTask()" data-toggle="tooltip" title="Delete Task"></i></li>
<p ng-show="tasks.length==0">No Tasks Available </p>
</ol>
</div>
</form>
</div>
</body>
JS CODE
var todoApp = angular.module('todoApp',[]);
todoApp.controller('addTaskController',function($scope){
$scope.tasks = [];
$scope.addTask = function() { // Function to add a task to list
if($scope.newTask == null) {
alert("Please enter a task");
} else {
$scope.tasks.push($scope.newTask);
localStorage.setItem("storedTasks", JSON.stringify($scope.tasks));
$scope.newTask = null;
}; // add() ends
}
$scope.deleteTask = function() {
$scope.tasks.splice(this.$index, 1);
localStorage.removeItem("storedTasks");
};
$scope.init = function() {
$scope.retrievedData = localStorage.getItem("storedTasks");
if($scope.retrievedData != null) {
$scope.tasks.push($scope.retrievedData);
} else {
tasks.length==0;
}
}
});
Before Page Reload
After Page Reload
How can i fix this
RetrievedData is an array you have to iterate over and push every item to the tasks object. What you are doing now is dumping the whole array into a single task.
if($scope.retrievedData != null){
$scope.retrievedData.forEach(function(item){
$scope.tasks.push(item);
})
}
Since you can only store string in local storage, which you did via JSON.stringify(), you need to undo it via JSON.parse(text[, reviver]) and then iterate over it.

AngularJS doesn't update view until refresh?

I am currently facing a problem, which has to do with views. I am making an app, which allows for users to create polls. When the poll that a user creates is submitted, I call a POST route to store it:
$scope.userVal = Auth.getCurrentUser();
$http.post('/api/users/update' + $scope.userVal._id, {polls: $scope.polls}).success(function(res){
//console.log("res: ", res);
});
Essentially, I get the user info,and use his id to store the new poll in a schema-defined value called polls.
Now, when a user clicks a button, I display the polls that were created via a ng-view:
$scope.pollView= function(){
$scope.userVal2 = Auth.getCurrentUser();
$scope.userVal2 = $scope.userVal2.polls;
$scope.button = true;
};
In the html, I simply iterate over $scope.userVal2. My problem comes when I try to view a newly created poll. The poll does not initially show up, but if I refresh the page, then it shows up. Is there any reason for this? Does this have to do with the async calls?
Any help would be appreciated!
edit:
Controller:
'use strict';
angular.module('voteApp')
.controller('WallCtrl', function ($scope, $http, Auth) {
$scope.items = [];
$scope.title;
$scope.button = false; //set default to the new poll
$scope.polls = [];
$scope.items.push({id:1, upvotes:0, text:""});
$scope.items.push({id:2, upvotes:0, text:""});
$scope.addOptions = function(){
$scope.items.push({id:$scope.items.length +1, upvotes:0, text:""});
};
$scope.process = function(name, values){
$scope.polls.push({title:name, options:values});
$scope.title = ""; //reset the values for the next poll
$scope.items = [];
$scope.items.push({id:1, upvotes:0, text:""});
$scope.items.push({id:2, upvotes:0, text:""});
$scope.userVal = Auth.getCurrentUser();
$http.post('/api/users/update' + $scope.userVal._id, {polls: $scope.polls}).success(function(res){
//console.log("res: ", res);
});
};
$scope.newView= function(){
$scope.button = false;
};
$scope.pollView= function(){
$scope.userVal2 = Auth.getCurrentUser().polls
$scope.button = true;
};
$scope.delete = function(val){
$scope.polls = $scope.polls.filter(function(returnableObjects){
return returnableObjects.title !== val.title;
});
};
});
html:
<div ng-include="'components/navbar/navbar.html'"></div>
<header class="hero-unit" id="banner">
<div class="container">
<h1>Dashboard</h1>
<p class="lead">What would you like to do today?</p>
<button ng-click="newView()" type="button" class="btn btn-lg newpoll">New Poll</button>
<button ng-click="pollView()"type="button" class="btn btn-lg mypolls">My Polls</button>
</div>
</header>
<div ng-show= "!button">
<form name="form" ng-submit="process(title, items)">
<h2 class="col-md-12 text-center">New Poll</h1>
<h5 class="col-md-12 text-center">Name your poll.</h1>
<input name="pollname" ng-model="title"type="text" class="form-control input_width" placeholder="Poll Name" required>
<br>
<h5 class="col-md-12 text-center">Options</h1>
<div ng-repeat="item in items">
<p>
<input name = "{{item.id}}" ng-model="item.text" type="text" class="form-control input_width" placeholder="Option {{item.id}}" required>
</p>
</div>
<br>
<div class="text-center">
<button type="button"ng-click="addOptions()" class="btn options" formnovalidate>More Options</button>
</div>
<br>
<div class="text-center">
<button type="submit" class="btn button" validate>Submit</button>
</div>
</form>
</div>
<div ng-show="button" >
<br>
<div ng-repeat="poll in userVal2">
<div class="polldeco">
{{poll[0].title}}
<button class="btn buttondeco" ng-click="delete(poll)">Delete</button>
</div>
</div>
</div>
Some ideas:
$scope.userVal2 = Auth.getCurrentUser().polls is using the old version prior to the creation of a new poll? Maybe this could be changed to something like Auth.getCurrentUser().then(...). Either way, ensure that the call to getCurrentUser() is returning new data.
ng-view is cached. When a template is initially requested, it gets stored in the $templateCache. If this template is rendered on the backend for display in as a partial (eg: ng-view) and it is not static content, then you will have to invalidate the cache to update the view.
Consider having the backend return the new poll from $http.post('/api/users/update' ...) and adding it to the list used by ng-repeat. Something like:
$scope.process = function(name, values) {
$scope.polls.push({title:name, options:values});
...
$http.post('/api/users/update' + $scope.userVal._id, {polls: $scope.polls}).success(function(poll){
$scope.polls.push(poll);
});
};
...
<div ng-repeat="poll in polls">
<div class="polldeco">
{{poll[0].title}}
<button class="btn buttondeco" ng-click="delete(poll)">Delete</button>
</div>
</div>

angular function gets spammed on load

I have the following controller:
app.controller('SignUpController', ['$http','$sessionStorage','api', '$scope','$state', '$log', 'Session','clientSocket', function ($http, $sessionStorage, api, $scope,$state, $log, Session, clientSocket) {
var signupCtrl = this;
signupCtrl.getRandomPerson = function () {
var isGuy = Math.floor((Math.random() * 2));
if(isGuy == 1 || isGuy == 0){
var picture = Math.floor((Math.random()*9));
return 'img/guys/guy-'+picture+'.jpg';
}else{
var picture = Math.floor((Math.random()*10));
return 'img/guys/woman-'+picture+'.jpg';
}
}
}]);
With the following html:
<div class="container w-xxl w-auto-xs" ng-controller="SignUpController as signUpCtrl" ng-init="app.settings.container = false;">
<div class="m-b-lg">
<div class="bg-white p-md">
<div class="block m-t text-center m-b-xl">
<img src="{{signUpCtrl.getRandomPerson()}}" alt="Company Logo" class="img-circle" style="display: inline-block">
</div>
<form name="form" class="form-validation">
<div class="list-group list-group-sm">
<div class="list-group-item">
<input placeholder="Name" class="form-control no-border" ng-model="user.name" required>
</div>
<div class="list-group-item">
<input type="email" placeholder="Email" class="form-control no-border" ng-model="user.email" required>
</div>
<div class="list-group-item">
<input type="password" placeholder="Password" class="form-control no-border" ng-model="user.password" required>
</div>
</div>
<div class="checkbox m-b-md m-t-none">
<label class="i-checks">
<input type="checkbox" ng-model="agree" required><i></i> Agree the <a href>terms and policy</a>
</label>
</div>
<button type="submit" class="btn btn-lg btn-primary btn-block" ng-click="signup()" ng-disabled='form.$invalid'>Sign up</button>
<div class="line line-dashed"></div>
<p class="text-center"><small>Already have an account?</small></p>
<a ui-sref="access.signin" class="btn btn-lg btn-default btn-block">Sign in</a>
</form>
</div>
</div>
<div class="text-center" ng-include="'tpl/blocks/page_footer.html'">
{% include 'blocks/page_footer.html' %}
</div>
When i am loading this page the function getRandomPerson gets fired over 10 times. Sometimes so much that angular throws the following execption:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [[{"msg":"fn: expressionInputWatch","newVal":"img/guys/guy-2.jpg","oldVal":"img/guys/guy-1.jpg"}],[{"msg":"fn: expressionInputWatch","newVal":"img/guys/guy-6.jpg","oldVal":"img/guys/guy-2.jpg"}],[{"msg":"fn: expressionInputWatch","newVal":"img/guys/guy-1.jpg","oldVal":"img/guys/guy-6.jpg"}],[{"msg":"fn: expressionInputWatch","newVal":"img/guys/guy-4.jpg","oldVal":"img/guys/guy-1.jpg"}],[{"msg":"fn: expressionInputWatch","newVal":"img/guys/guy-8.jpg","oldVal":"img/guys/guy-4.jpg"}]]
http://errors.angularjs.org/1.3.14/$rootScope/infdig?p0=10&p1=%5B%5B%7B%22m…guys%2Fguy-8.jpg%22%2C%22oldVal%22%3A%22img%2Fguys%2Fguy-4.jpg%22%7D%5D%5D
at REGEX_STRING_REGEXP (angular.js:63)
at Scope.$get.Scope.$digest (angular.js:14281)
at Scope.$get.Scope.$apply (angular.js:14506)
at done (angular.js:9659)
at completeRequest (angular.js:9849)
at XMLHttpRequest.requestLoaded (angular.js:9790)
Can anyone tell me whats going on?
The issue is that many digests might run on a particular scope within the page...even just to render once
Because every digest is seeing a new value from your function, it forces another digest. Thus you are creating an infinte loop
Just assign a scope variable randomImage and get that value returned from function, instead of placing function in the html
And as pointed out use ng-src so that final src gets set with a proper value after it is compiled. Otherwise you will have strange invalid path requests made to server
// will only run once when controller initializes
signupCtrl.randomImage = getRandomPerson();
// no need to be on scope since using it privately
var getRandomPerson = function() {
var isGuy = Math.floor((Math.random() * 2));
if(isGuy == 1 || isGuy == 0){
var picture = Math.floor((Math.random()*9));
return 'img/guys/guy-'+picture+'.jpg';
}else{
var picture = Math.floor((Math.random()*10));
return 'img/guys/woman-'+picture+'.jpg';
}
}
HTML
<!-- No src so browser won't make request to invalid path -->
<img ng-src="{{signUpCtrl.randomImage }}">
You have a src binding to your function, if you intend to do this you should be using ng-src so it won't be compiled before it is ready to be consumed.

Categories