Data doesn't bind when submitting form - javascript

When I refresh the page the correct values come up. I want the list of 'gists' to automatically update when the form is submitted.
The global #todone is set that way because I receive an undefined error when I set it as 'todone'. It may be unrelated.
app.factory "To_done", ["$resource", ($resource) ->
$resource("/to_dones", {}, {update: {method: "PUT"}})
]
#MainCtrl = ["$scope", "To_done", ($scope, To_done) ->
$scope.to_dones = To_done.query()
$scope.addTodone = ->
#todone = To_done.save($scope.newTodone)
$scope.to_dones.push(#todone)
$scope.newTodone = {}
]
<div ng-controller="MainCtrl">
<form ng-submit="addTodone()">
<input type="text" ng-model="newTodone.gist">
<input type="submit" value="Add">
</form>
<ul>
<li ng-repeat="todone in to_dones">
{{todone.gist}}
</li>
</ul>
</div>

To_done.save($scope.newTodone) is asynchronous. You need to register a callback function to get the value returned by your POST.
var todone = To_done.save($scope.newTodone, function() {
//success callback - optional
$scope.to_dones.push(todone);
}, function() {
//error callback - optional
});
$scope.newTodone = {};
You can add arguments to the callback methods if you need more informations about the answer received from your service. More details here : http://docs.angularjs.org/api/ngResource.$resource

Related

Using 'Ng-If' "breaks" program on a $('#x').change or an angularfire $add

I've noticed two instances in my code where using ng-if causes my program to start working. On one, I do an ng-if="isOwnProfile", for an image-upload toolbar.
Using the ng-if causes the event listener to stop working. Code example:
$scope.myOwnProfile = false;
if (userLoggedIn === userUID) {
console.log('my images');
$scope.myOwnProfile = true;
} else {
console.log('not my images');
}
$("#image-upload").change(function(e) {
$scope.myOwnProfile = true;
var file = e.target.files[0];
var imageRef = firebase.storage().ref...
and in HTML:
<section ng-if="myOwnProfile">
<input id="image-upload" type="file" accept="image/*"> <br /><br />
</section>
In this case the event listener will stop working and not respond.
Another case is where you add a message to the page (and firebase).
Code:
$scope.addMessage = function(){
var date = new Date();
$scope.messages.$add({
timestamp: (date.getMonth() + 1) + "/" + date.getDate() + "/" + date.getFullYear(),
from: $scope.visitorRealName.name,
content: $scope.message
});
$scope.message = '';
};
HTML:
<section ng-if="AreWeFriends === true || myOwnProfile === true">
<form ng-submit="addMessage()">
<input ng-model="message">
<button type="submit">Add Message</button>
</form>
</section>
In the second case I get an error from Firebase "Key content was undefined. Cannot pass undefined in JSON. Use null instead".
I can't determine why using ng-if causes this to happen? What I do is set the user's profile to true whether they are a) a friend or b) it's the person's own profile (which is why I change $scope).
That's because the ngIf directive creates it's own child scope.
The ngIf directive creates it's own scope, so the ngModel directive containing message is set on the scope created by the ngIf directive, not your controller.
When you access the value in your controller it's not there, so it's undefined. You are essentially passing undefined to your content key inside your object you're adding to your messages so Firebase complains.
To fix it i'd recommend using the controller as syntax so that you can reference the controller, or use the ngShow directive, which doesn't create it's own child scope.
Here are a few examples of what happens:
(function() {
'use strict';
angular.module('app', []);
})();
(function() {
'use strict';
angular.module('app').controller('MainController', MainController);
MainController.$inject = ['$scope'];
function MainController($scope) {
var vm = this;
$scope.test1 = test1;
$scope.test2 = test2;
$scope.test3 = test3;
$scope.test4 = test4;
function test1() {
// this is undefined because there is no property `message`
// on the $scope of this controller
alert($scope.message);
}
function test2() {
// this contains the value binded to the message property
// of this controller because we used the controller as syntax
alert(vm.message);
}
function test3(message) {
// because we are passing in the message value we can
// access it without caring where it came from
alert(message);
}
function test4() {
// the property `message` exists on this $scope because we
// used the ngShow directive instead of the ngIf
alert($scope.message4);
}
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="MainController as MainCtrl">
<h4>Without controller as syntax</h4>
<p>Does not work because message is not set on the controller's $scope, it's set on the scope created by the ngIf directive</p>
<form ng-if="true">
<input ng-model="message">
<button ng-click="test1()">Submit</button>
</form>
<hr>
<h4>With controller as syntax</h4>
<p>Works because message is set on the controller so we can access it using `this` in our MainController</p>
<form ng-if="true">
<input ng-model="MainCtrl.message">
<button ng-click="test2()">Submit</button>
</form>
<hr>
<h4>Without controller as syntax but passing the message value into our function</h4>
<p>Works because although message is set on the scope created by the ngIf directive, we are passing it to test3 in our MainController.</p>
<form ng-if="true">
<input ng-model="message">
<button ng-click="test3(message)">Submit</button>
</form>
<hr>
<h4>With ngShow directive instead of ngIf</h4>
<p>Works because message is set on $scope from our contoller</p>
<form ng-show="true">
<input ng-model="message4">
<button ng-click="test4()">Submit</button>
</form>
</div>

Persisting form data when user navigates away from page in Angular

I would like to persist the data entered in a form so that the information entered will still display in the respective fields if the user clicks the back button and then subsequently returns to the form. I've tried using this Stack Overflow answer as a model, but am not having any luck: https://stackoverflow.com/a/16806510/640508
I'm using the Controller As syntax.
Here's my adapted code:
Controller:
angular.module('myApp')
.controller('ContactFormCtrl', ['formMemory', '$http', function (formMemory, $http) {
var contactForm = this;
contactForm.contact=formMemory;
formMemory.set();
formMemory.get();
// . . .
}]);
Service:
angular.module('formMemory.fact', [])
.factory('formMemory', function () {
var contact = {};
return {
get: function () {
return contact;
},
set: function (value) {
contact = value;
},
reset: function () {
contact = {};
}
};
HTML:
<h1><small>ContactInformation</small></h1>
<form name="myForm" novalidate >
<div class="row">
<div class="col-sm-4 form-group">
<label class="control-label" for="first-name">First Name</label>
<input type="text" id="first-name" name="firstName" ng-model="contactForm.contact.firstName"
placeholder="First Name" class="form-control">
</div>
// . . .
app.js:
angular.module('myApp', [
'formMemory.fact',
//. . .
]);
The factory formMemory returns an anonymous object, with 3 functions attached. You aren't using the correct syntax for accessing these functions.
To access the saved data, you would want to set your controller variable to the return value of the get() function, like so:
contactForm.contact = formMemory.get();
and to save the data if you navigate away, you should be passing the contact in as a parameter to the set(value); most likely, you would do this in the $routeChangeStart.
$scope.$on('$routeChangeStart', function() {
//we are leaving the page, so let's save any data we have
formMemory.set(contactForm.contact);
}

How to create own angular service with XHR properly?

I am very new about AngularJS things. Need to do file upload with other datas in form, I found some scripts and angular plugins but I am using my own service calls $xhr. I was able to send file but i got error, bug(not real error-bug, i just named like that) or i can not use AngularJS properly. Here it is:
.
JS
var app = angular.module('ngnNews', []);
app.factory('posts', [function () {...}]); // I reduced the codes
app.factory('$xhr', function () {
var $xhr = { reqit: function (components) { ... //My Xml HTTP Request codes here }}
return $xhr;
});
app.controller('MainCtrl', ['$http','$scope','$xhr','posts',
function ($http, $scope, $xhr, posts) {
$scope.posts = posts.posts;
$scope.files = [];
var newPost = { title: 'post one', upvotes: 20, downvotes: 5 };
$scope.posts.push(newPost);
$scope.addPost = function () {
$xhr.reqit({
form: document.getElementById('postForm'),
callbacks: {
success: function (result) {
if (result.success) {
console.log($scope.posts); //[FIRST OUT]
$scope.posts.push(result.post);
$scope.title = '';
console.log($scope.posts); //[SECOND OUT]
}
}
},
values: { upvotes: 0, downvotes: 0 },
files: $scope.files
});
...
}
}]);
.
HTML
<form action="/Home/FileUp" id="postForm" method="post" enctype="multipart/form-data">
<div class="form-group input-group">
<span class="input-group-addon">Post Title</span>
<input name="title" class="form-control" type="text" data-ng-model="title" />
</div>
<ul>
<li ng-repeat="file in files">{{file.name}}</li>
</ul>
<button class="btn btn-primary" type="button" data-ng-click="addPost()">Add New</button>
</form>
SCREEN
Sample post displayed in list
.
PROBLEMS
When I click first time Add New button everything works well until $scope.posts.push(result.post);. In console, [SECOND OUT] is here:
First object has $$hashKey but second object which sent from server(added by $scope.posts.push(result.post); function) doesn't have. I want to know why is this happening? But it's not only weird thing, when I second time click Add New button, everything completed successfully (No new logs in console, adding new post to list shown screen image above).
MAIN PROPLEM
I pushed returned value from the server but post list(in screen) is not affected when first click.
QUESTIONS
- What is happening? or
- What am I doing wrong? Thanks for any explanation.
You are doing nothing wrong with respect to $$hashkey if that is your concern. When you use ng-repeat with array of objects angular by default attaches a unique key to the items which is with the property $$hashkey. This property is then used as a key to associated DOM elements with the corresponding item in the array by identity. Moving the same object in array would move the DOM element in the same way in the DOM. You can avoid this (addition of additional property on the object by angular) by using track by with ng-repeat by providing a unique key on the object or a mere $index. So with that instead of creating a unique key and attaching it to $$haskey property angular will use the unique identifier you have provided to associate the DOM element with the respective array item.
ng-repeat="post in posts track by $index"
or (id you have a unique id for each of the object in the array, say id then)
ng-repeat="post in posts track by post.id"
And since you say you are using my xml http request code here, i am assuming it is not within the angular context so you would need to manually perform the digest cycle by using $scope.$apply() is on of those ways.
$scope.addPost = function () {
$xhr.reqit({
form: document.getElementById('postForm'),
callbacks: {
success: function (result) {
if (result.success) {
$scope.posts.push(result.post);
$scope.title = '';
$scope.$apply();//<-- here
}
}
},
But ideally you could wrap your xhr implementation with a $q and if you pass $q promise from your api, you wont need to perform a manual $scope.$apply() everywhere. Because $q promise chaining will take care of digest cycle invocation.

Scope not updating changes in the model

I have an expandable form that generates an object with two attributes, a title and description. This object successfully submits to my database as a json object. I'm currently using an Angular (1.3.2) front end that interacts with Tastypie as the interface layer with my Django (1.7) backend. The problem is that I never observe updates to my home page after adding a new object to the db. I need to refresh the page for the object to appear which is not ideal.
home.html
<div class="protocol-list-container">
<div ng-app="protocolApp"
id="protocol-list">
<div class="new-protocol-container" ng-controller="protoCtrl">
<h4>Add New Protocol</h4>
<button type="button"
ng-click="toggle()"
id="id_new">
<span class="glyphicon glyphicon-plus"></span>
</button>
<div ng-hide="visible" class="protocol-new">
<form name="newProtocolForm" novalidate>
<input type="text"
id="id_new_title"
placeholder="Title"
ng-model="protocol.title"
required /><br>
<input type="text"
id="id_new_desc"
placeholder="Description"
ng-model="protocol.description"
required /><br><br>
<input type="submit"
id="id_submit_new_protocol"
value="New Protocol"
ng-click="submit(protocol)"
ng-disabled="newProtocolForm.$invalid">
</form>
{% verbatim %}
<pre>form = {{ protocol | json}}</pre>
{% endverbatim %}
</div>
<div class="protocol">
<h4>My Protocols</h4>
<li ng-repeat="protocol in protocols">
{% verbatim %}
<div><span ng-bind="protocol.title"></span></div>
{% endverbatim %}
<div> - <span ng-bind="protocol.description"></span>
</li>
<br>
</div>
</div>
</div>
app.js
angular.module('protocolApp', [])
.factory('protocolFactory', ['$http', function($http) {
var urlBase = '/api/v1/protocol/';
var protocolFactory = {};
protocolFactory.getProtocols = function() {
console.log('getProtocols called');
return $http.get(urlBase);
};
protocolFactory.addProtocol = function(protocol) {
console.log('addProtocol called');
return $http.post(urlBase, protocol);
};
return protocolFactory;
}])
.controller('protoCtrl', ['$scope', 'protocolFactory',
function ($scope, protocolFactory) {
$scope.visible = true;
var self = this;
getProtocols();
function getProtocols() {
protocolFactory.getProtocols()
.success(function(data) {
$scope.protocols = data;
})
.error(function(error) {
console.log('error retrieving protocols');
});
}
$scope.toggle = function() {
$scope.visible = !$scope.visible;
var self = this;
var protocol = {};
self.submit = function() {
var protocol = {title: self.title, description: self.description};
console.log('clicked submit with ', self.protocol);
protocolFactory.addProtocol(self.protocol)
.success(function(response) {
console.log('protocol added');
$scope.protocol = null;
})
.error(function(error) {
console.log('post to api failed');
});
// gives the behavior I want, but ultimately crashes chrome
// $scope.$watch('protocols', function(newVal, oldVal) {
// protocolFactory.getProtocols()
// .success(function(data) {
// $scope.protocols = data;
// console.log('watcher data', data);
// });
// }, true);
};
};
}]);
I've done some testing with a $scope.$watch function (commented out), but this either shows the new object and never stops (true removed) or does not update (but tells me that there is an extra object in the data based on the console statement) (true present).
Any help would be appreciated.
When the database gets updated, how does the front end know that it should get the latest data unless we tell it to ? You don't have some kind of sockets between the server and front end, looking for events and making the front end to get the latest data...
So, When you post the data to backend and database got updated, make a call to getProtocols(), in the success callback of submit.
In your case of using $watch(), you are repeatedly getting the protocols from backend, which updated the scope variable, which again fired the callback repeatedly and browser crashed.

Updating multi-model form from Angular to Sinatra

I'm currently having an issue with updating a form in Angular and pushing the update through to Sinatra.
It is supposed to:
When clicked, the form to edit the current item is shown (current data for each field is displayed from the item scope).
When submitted, it is attempting to update to a different scope (updateinfo). I am not sure but do I need a way of using multiscope or one scope to allow it to update?
At present the script sends the correct downloadID parameter, but the JSON from the scope submitted is as I believe, incorrect.
Also, I'm not sure whether the Sinatra app.rb syntax is correct, for someone new to these frameworks, it has been hard to find useful documentation online.
If anybody could help it would be very much appreciated.
downloads.html
<div ng-show="showEdit">
<form ng-submit="updateinfo(item.downloadID); showDetails = ! showDetails;">
<div class="input-group"><label name="title">Title</label><input type="text"
ng-model="item.title"
value="{{item.title}}"/></div>
<div class="input-group"><label name="caption">Download caption</label><input type="text"
ng-model="item.caption"
value="{{item.caption}}"/>
</div>
<div class="input-group"><label name="dlLink">Download link</label><input type="url"
ng-model="item.dlLink"
value="{{item.dlLink}}"/>
</div>
<div class="input-group"><label name="imgSrc">Image source</label><input type="url"
ng-model="item.imgSrc"
value="{{item.imgSrc}}"/>
</div>
<!-- download live input types need to be parsed as integers to avoid 500 internal server error -->
<div class="input-group"><label name="imgSrc">
<label name="dlLive">Download live</label><input type="radio" ng-model="download.dl_live"
value="1"/>
<label name="dlLive">Not live</label><input type="radio" ng-model="download.dl_live"
value="0"/></div>
<div class="input-group"><label name="imgSrc"><input type="submit"/></div>
</form>
controllers.js
$scope.loadData = function () {
$http.get('/view1/downloadData').success(function (data) {
$scope.items = data;
});
};
$scope.loadData();
$scope.updateinfo = function(downloadID) {
id = downloadID
var result = $scope.items.filter(function( items ) {
return items.downloadID == id;
});
console.log(result);
updatedata = $scope.items
$http({
method : 'PUT',
url : '/view1/downloadedit/:downloadID',
data : result
});
};
app.rb
#edit download
put '/view1/downloadedit' do
puts 'angular connection working'
ng_params = JSON.parse(request.body.read)
puts ng_params
#download = Download.update(ng_params)
end
The wrong scope was attempting to be used. Once the scope was corrected to items, the correct JSON was being routed:
$scope.updateinfo = function(downloadID) {
id = downloadID
var result = $scope.items.filter(function( items ) {
return items.downloadID == id;
});
console.log(result);
updatedata = $scope.items
$http({
method : 'PUT',
url : '/view1/downloadedit/:downloadID',
data : result
});

Categories

Resources