On my page I have bs-table. The data comes from api call. By click on row I send new api call to retrieve row data from db. Then I set scope variable for res data and render it on a page
$('#table').on('click-row.bs.table', function (e, row, $element) {
$('.success').removeClass('success');
$($element).addClass('success');
var indexId = $table.find($element).data('index');
var rowData = $table.bootstrapTable('getData')[indexId];
$scope.id = rowData.id;
$http.get(url + $scope.id)
.then(function (res) {
$scope.rowData = res.data.model;
console.log($scope.rowData);
$scope.rowKeys = Object.keys($scope.rowData);
});
$scope.$apply();
});
html:
<form style="padding: 15px" ng-submit="submitForm()">
<div class="form-group row">
<div ng-repeat="k in rowKeys | filter: '!id'" ng-model="rowValue">
<label for="rowValue" class="col-sm-2">
<!--{{k | hide:'.name'}}:-->
{{k }}:
</label>
<div class=" col-sm-2">
<input class="form-control rowValue" id="rowValue" value="{{rowData[k]}}"/>
</div>
</div>
</div>
<button type="submit" class="btn btn-default" ng-if="rowData" >Submit</button>
Then thru ng-submit I want to send back changes which have been made in that form
$scope.submitForm = function() {
$scope.$watch('rowData', function(newValue, oldValue) {
console.log('being watched oldValue:', oldValue, 'newValue:', newValue);
}, true);
$http({
method : 'PUT',
url : url + $scope.id,
data : $scope.rowData, //form
headers : {'Content-Type': 'application/json'}
})
.then(function (res) {
//console.log(res);
//console.log($scope.rowData);
return res;
});
};
As you can see I've set $watch that to follow for changes in scope variable, but the problem is the console log returns same values for oldValue and newValue. Could anybody explain me where is my mistake? I appreciate any help
You're not binding the values to anything. Instead of using value="{{rowData[k]}}" on your input element, use ng-model: ng-model="rowData[k]".
You're calling $scope.$apply(); before the request has a chance to finish. You need to put $scope.$apply(); within the then() callback.
$http.get('stuff').then(function(response){
//stuff
$scope.$apply();
});
Related
I have a form to enter a list of key value pairs. When I enter data into the input fields or add a new keyvalue pair everything displays fine on the client side and I can see the Model updating. The problem comes when I go to save the newly created list. The list get passed to the angular save function just fine with all the data in place. The problem occurs between the angular save function and my MVC controller save function. The right number of key value pairs get sent to the MVC controller functions parameters, but all of the information has now been set to null.
So on the client side my model looks like this.
[{"Key":"this","Value":"has"},{"Key":"data","Value":"in"},{"Key":"it","Value":"see"}]
which is what I want, but when it reaches my MVC controller as a parameter it looks like this.
[{"Key":null,"Value":null},{"Key":null,"Value":null},{"Key":null,"Value":null}]
Which is not what I want. Any help with this will be greatly appreciated. Thank You.
Here is my MVC controller function.
public JsonResult SaveSettings(List<KeyValuePair<string, string>> replacementPaths)
{
JobSchedulerConfig config;
config = Biz.GetConfig();
config.ReplacementPaths = replacementPaths;
return null;
}
My Angular controller and save logic.
$scope.save = function () {
SettingsService.saveSetting($scope.settings)
.success(function (data) {
//alert(data);
})
.error(function (error) {
$scope.status = 'Unable to load data: ' + error.message;
});
};
SettingsApp.factory('SettingsService', ['$http', function ($http) {
var SettingsService = {};
SettingsService.getSettings = function () {
return $http.get('#Url.Action("GetReplacementPaths", "Setting")');
};
SettingsService.saveSetting = function (data) {
//alert(data);
alert(data.toSource());
//data = angular.stringify(data);
return $http.post('#Url.Action("SaveSettings", "Setting")', data );
};
return SettingsService;
}]);
And my view markup.
<div ng-app="SettingsApp">
<div ng-controller="SettingsController">
<div ng-repeat="kvp in settings">
<input ng-model="kvp.Key" />
<input ng-model="kvp.Value" />
<button ng-click="delete(settings, kvp)">Delete</button>
</div>
<button class="btn btn-default" ng-click="addSetting()">Add Setting</button>
<button type="submit" name="config" ng-click="save()" class="btn btn-default btn-primary">Save Config</button>
{{settings}}
</div>
</div>
Again thanks for any help.
I am currently working on an app that retrieves data on the of change of $routeParams. So here's how it begins:
function artistCtrl($scope, $http, $location, dataFactory, $routeParams){
$scope.artistName = $routeParams.artistname
$scope.$watch('artistName', function(newValue, oldValue){
$scope.artistInfo = dataFactory.getArtist(newValue)
})
$scope.artistInfo = {
artist_name: dataFactory.artistInfo.artist_name,
artist_genre: dataFactory.artistInfo.artist_genre,
artist_imageurl: dataFactory.artistInfo.artist_imageurl,
artist_bio: dataFactory.artistInfo.artist_bio
};
}
The callback for $watch here is run. dataFactory.getArtist retrieves newValue from my database which is being done successfully. That is done like this:
dataFactory.js
dataFactory.getArtist = function(artist){
return dataFactory.checkDb(artist).then(function(dbData){
if(dbData.data != "No data"){
dataFactory.artistInfo = dbData.data[0]
}
return dbData.data[0]
})
}
dataFactory.artistInfo = "";
dataFactory is a factory I created in another file.
artistpage.html
<div class="container this">
<div class="row">
<div class="col-sm-6">
<div><h1>{{artistInfo.artist_name}}</h1></div>
<div rate-yo id='stars' rating="myRating" class="col-sm-4"></div>
<div id='reviews'>23 Reviews</div>
<div><h2>{{artistInfo.artist_genre}}</h2></div>
<div><p>{{artistInfo.artist_bio}}</p></div>
<div><button type="button" class="btn btn-primary" ng-click="somefunc()">Submit a Review</button></div>
</div>
<div class="col-sm-6 reviews">
<div><img class="artistpageimage" src={{artistInfo.artist_imageurl}}></div>
</div>
</div>
</div>
I don't understand why my view isn't being updated. I am attempting to update $scope.artistName by assigning the returned dataFactory.getArtist(newValue)
and also by assigning the new data to dataFactory.artistInfo I have read about $apply, but I am having a hard time figuring out how to apply it in this context. Can anyone help?
Does getArtist return a promise or a value. If it's a promise try something like the below:
$scope.$watch('artistName', function(newValue, oldValue){
dataFactory.getArtist(newValue).then(function(value) {
$scope.artistInfo = value;
})
})
I think the problem is that dataFactory.getArtist(newValue) is returning a promise, which you're assigning directly to artistInfo. Try replacing it with:
dataFactory.getArtist(newValue).then(function (info) {
$scope.artistInfo = info;
});
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.
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
});
In my web app, There are many form on a page. I want to submit it with AngularJS for specific form.
In each of form, it need unique ID with Hidden Value to submit. But value="UNIQUE_ID" seen doesn't work in hidden input box in AngularJS.
My HTML
<div ng-app>
<div ng-controller="SearchCtrl">
<form class="well form-search">
<input type="text" ng-model="keywords" name="qaq_id" value="UNIQUE_ID">
<pre ng-model="result">
{{result}}
</pre>
<form>
</div>
</div>
This is js script
function SearchCtrl($scope, $http) {
$scope.url = 'qa/vote_up'; // The url of our search
// The function that will be executed on button click (ng-click="search()")
$scope.search = function() {
// Create the http post request
// the data holds the keywords
// The request is a JSON request.
$http.post($scope.url, { "data" : $scope.keywords}).
success(function(data, status) {
$scope.status = status;
$scope.data = data;
$scope.result = data; // Show result from server in our <pre></pre> element
})
.
error(function(data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
});
};
}
It may be that the only reason your code is not working is that $scope.keywords is a simple variable (with a text value) instead of an Object, which is required - see http://docs.angularjs.org/api/ng.$http#Usage
As angularJS works with variables within its own scope - its models, a form becomes just a way to interact with those models, wich can be sent via whatever method you want.
You can have a hidden field, yes, but in angularJS it isn't even necessary. You only need that information to be defined in the controller itself - randomly generated for each instance, or received from some other source.. Or you can define it yourself, upon the loading of the controller, for instance.
So (and only for sake of clarity) if you define a formData variable within your formCtrl:
Your HTML:
<div ng-app>
<div ng-controller="SearchCtrl">
<form class="well form-search">
<input type="text" ng-model="formData.title">
<input type="textarea" ng-model="formData.body">
<button ng-click="sendData()">Send!</button>
</form>
<pre ng-model="result">
{{result}}
</pre>
</div>
</div>
And your controller:
function SearchCtrl($scope, $http) {
$scope.url = 'qa/vote_up'; // The url of our search
// there is a formData object for each instance of
// SearchCtrl, with an id defined randomly
// Code from http://stackoverflow.com/a/1349426/1794563
function makeid()
{
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 5; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
$scope.formData = {
title: "",
text: ""
};
$scope.formData.id = makeid();
// The function that will be executed on button click (ng-click="sendData()")
$scope.sendData = function() {
// Create the http post request
// the data holds the keywords
// The request is a JSON request.
$http.post($scope.url, { "data" : $scope.formData}).
success(function(data, status) {
$scope.status = status;
$scope.data = data;
$scope.result = data; // Show result from server in our <pre></pre> element
})
.
error(function(data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
});
};
}
Also: If you wanted to set the unique id on the html itself, you could add an input type="hidden" and set it's ng-model attribute to formData.id, and whichever value you set it to, the model would have it binded. using a hidden input won't work, as the value attribute doesn't update the angularJS Model assigned via ng-model. Use ng-init instead, to set up the value:
HTML with 2 forms:
<div ng-controller="SearchCtrl" ng-init="formData.id='FORM1'">
<form class="well form-search">
<input type="text" ng-model="formData.title">
<input type="textarea" ng-model="formData.body">
<button ng-click="sendData()">Send!</button>
</form>
</div>
<div ng-controller="SearchCtrl" ng-init="formData.id='FORM2'">
<form class="well form-search">
<input type="text" ng-model="formData.title">
<input type="textarea" ng-model="formData.body">
<button ng-click="sendData()">Send!</button>
</form>
</div>
You can add a hidden field, but it accomplishes nothing - the ng-init attribute does everything you need.