I wanna use angular sortable on my app. But my model is dynamically populated from several json files with $http.get() function. All that ngSortable see from the model is just an empty array. And it won't get the new data from the JSON file. Is there any workaround for this?
$scope.jsons = ["data1.json", "data2.json"];
$scope.abc = [];
angular.forEach($scope.jsons, function(value, key){
$http.get(value).success (function(data){
$scope.abc.push(data);
});
});
$scope.sortableOptions = {
accept: function (sourceItemHandleScope, destSortableScope) {return true}
};
<div ng-model="abc" as-sortable="sortableOptions">
<div ng-repeat="x in abc" as-sortable-item>
<div as-sortable-item-handle>{{x.name}}</div>
</div>
</div>
I had the same problem with ng-sortable: everything worked fine with static data but not with JSON data that come asynchronous from $http.get().
There are two solutions:
Leave the controller as it and, in the html part, replace both occurrences of "abc" with "$parent.abc"
Instead of directly access the 'abc' array, use an intermediate object, like this:
$scope.tmpObject = {};
$scope.tmpObject.abc=[];
...
$http.get(value).success (function(data){
$scope.tmpObject.abc.push(data);
});
...
<div ng-model="tmpObject.abc" as-sortable="sortableOptions">
<div ng-repeat="x in tmpObject.abc" as-sortable-item>
<div as-sortable-item-handle>{{x.name}}</div>
</div>
</div>
use service $q
like
//first make a factory using $q
yourappname.factory("factoryname",function($http, $q){
var _getDetails=function(value){
var deferred = $q.defer();
$http.get(value).then(function(modal){
deferred.resolve(modal);
});
return deferred.promise;
};
return {
_getDetails:_getDetails
};
});
// then in your controller use this factory
$scope.jsons = ["data1.json", "data2.json"];
$scope.abc = [];
/**angular.forEach($scope.jsons, function(value, key){
$http.get(value).success (function(data){
$scope.abc.push(data);
});
});
***/
angular.forEach($scope.jsons, function(value, key){
var promiseData= factoryname._getDetails(value);
promiseData.then(function(result){
if(result.data)
{
$scope.abc.push(result.data);
}
});
});
$scope.sortableOptions = {
accept: function (sourceItemHandleScope, destSortableScope) {return true}
};
<div ng-model="abc" as-sortable="sortableOptions">
<div ng-repeat="x in abc" as-sortable-item>
<div as-sortable-item-handle>{{x.name}}</div>
</div>
</div>
Related
I searched for this but I did not get any answer as I want, please give me a solution, I want to use ng-init inside ng-repeat, ng-init should give me different response at every loop here is my HTML
<html>
<body ng-app="crmApp">
<div ng-controller="customerDetailController">
<div ng-repeat="clientDetail in client">
<p>{{clientDetail.name}}</p>
<div ng-init="seoDetails = getCustDetail(clientDetail.name)">
<p>{{seoDetails.cust_Name}}</p>
</div>
</div>
</div>
</body>
</html>
and my js is
<script>
var crmMain = angular.module('crmApp', ['ngRoute','ngMaterial']);
crmMain.controller('customerDetailController',function customerDetailController($scope, $http, customerDetailFactory,$window) {
$scope.client = [];
$scope.init = function () {
$scope.getCustomerData();
};
$scope.getCustomerData = function () {
customerDetailFactory.getCustomerDetailData().then(function
(response) {
$scope.client = response.data;
});
};
$scope.getCustDetail = function (Name) {
var custDetail = [];
custDetail = customerDetailFactory.getCustomerDetailData(Name).then(function (response) {
alert(response.data.cust_Name);
return response.data;
});
return custDetail;
};
$scope.init();
});
crmMain.factory('customerDetailFactory', ['$http', function ($http) {
var factory = {};
var url = 'phpFile/customerDetail.php';
factory.getCustomerDetailData = function (Name) {
return $http({
method: 'POST',
url: url,
data: {
'functionName': 'clientDetailPage',
'customerName': Name
}
});
};
return factory;
}]);
</script>
In inside getCustDetail function I was given alert in there it 'll show name, but I don't know why it not showing in HTML.is anything wrong I did?
I have got one solution for this, I think I have to use Promises for this, but I don't know how to use it can anyone help me in this?
You cannot use ng-init for this purpose.
You've to do the data fetching inside the controller itself. That is like,
customerDetailFactory.getCustomerDetailData()
.then(function(response) {
$scope.client = response.data;
// for each clients, fetch 'seoDetails'
$scope.client.forEach(function(client) {
customerDetailFactory.getCustomerDetailData(client.name)
.then(function (response) {
// I hope response.data contains 'cust_Name'
client.seoDetails = response.data;
})
});
});
Now, in the view, you can directly use the seoDetails property
<div ng-repeat="clientDetail in client">
<p>{{clientDetail.name}}</p>
<p>{{clientDetail.seoDetails.cust_Name}}</p>
</div>
I have a feeling that this should be very simple thing to do but I can't figure it out at the moment.
I am learning AngularJS by building a simple podcast app. So far I've managed to convert an XML file from url to JSON object.
Now I would like to loop thru each object of the "story" and display data such as title and image url. (see img below)
starter.controller('fox', function($scope, $http){
$http.get('http://api.npr.org/query?id=57&apiKey=i've removed the key)
.success(function(data, status, headers, config){
var x2js = new X2JS();
var jsonOutput = x2js.xml_str2json(data);
console.log(jsonOutput);
$scope.title = jsonOutput.nprml.list.story[0]['title'];
})
.error(function(data, status, headers, config){
alert('There is a problem');
})
});
<div class="list" ng-repeat=" ? ">
{{title}}
</div>
The code below only renders the first object as I've set that manually - story[0]['title'] and I am unsure hot to loop thru the list.
In jQuery I would usually do for each loop and append the result in a div.
it should be something like this.
starter.controller('fox', function($scope, $http){
$http.get('http://api.npr.org/query?id=57&apiKey=i've removed the key)
.success(function(data, status, headers, config){
var x2js = new X2JS();
var jsonOutput = x2js.xml_str2json(data);
console.log(jsonOutput);
$scope.stories = jsonOutput.nprml.list.story;
})
.error(function(data, status, headers, config){
alert('There is a problem');
})
});
<div class="list" ng-repeat="story in stories">
{{story.title}}
{{story.link}}
</div>
The main thing I want to do here is:
When the form is submitted, a http get request will be done (VerbController)
On success, a JSON string is returned
I copy the JSON string into a factory object (called VerbFactory)
I want to output the content of the JSON string in a div through another controller (OutputController), I took the attribute "name" as an example here.
To achieve this (point 4), I watched for a change in the VerbFactory object and when the JSON string after requesting gets loaded into the object, I want to store it in a variable of the OutputController, so that I can make an expression for it in my HTML.
But it does not work right now. It seems that this.verb is in another scope than the controller scope. I have difficulties understand the difference between $scope and this here, even though I have read a decent amount of articles about the difference between those two.
How do I solve this problem? Do I miss something obvious?
NB: I added some jQuery that puts the attribute "name" of the JSON into a debug div, and it works as expected. But the AngularJS expression {[{outputCtrl.verb["#attributes"]["name"]}]} does not work.
HTML:
<div class="container">
<div class="row">
<div id="debug" class="col-xs-12 col-sm-12">
</div>
<div class="col-xs-12 col-sm-12" ng-controller="OutputController as outputCtrl">
{[{outputCtrl.test}]}
{[{outputCtrl.verb["#attributes"]["name"]}]}
</div>
</div>
</div>
JS:
(function() {
var app = angular.module('LG', []).config(function($interpolateProvider){
$interpolateProvider.startSymbol('{[{').endSymbol('}]}');
});
app.factory("VerbFactory", function(){
var json = {};
var available = false;
return {
getJSON: function() {
return json;
},
setJSON: function(newObj) {
angular.copy(newObj, json);
available = true;
},
isAvail: function() {
return available;
},
resetAvail: function() {
available = false;
}
};
});
app.controller("VerbController", ['$http', 'VerbFactory', function($http, VerbFactory){
this.verb = "";
this.requestVerb = function() {
VerbFactory.resetAvail();
var that = this;
$http.get('/request/' + that.verb).
success(function(data) {
VerbFactory.setJSON(data);
}).
error(function() {
});
this.verb = "";
};
}]);
app.controller("OutputController", ['$scope', 'VerbFactory', function($scope, VerbFactory){
this.test = "Test!";
$scope.$watch(VerbFactory.isAvail, function(){
this.verb = VerbFactory.getJSON();
$('#debug').append('<p>'+ this.verb["#attributes"]["name"] +'</p>');
});
}]);
})();
this inside of $scope.$watch callback refers to the callback scope, not the outer scope of OutputController. Use var self = this to refer to the OutputController.
ControllerAs Syntax
OutputController.js
var self = this
$scope.$watch(VerbFactory.isAvail, function(){
self.verb = VerbFactory.getJSON();
//etc
});
Regular Controller Syntax
OutputController.js
$scope.$watch(VerbFactory.isAvail, function() {
$scope.verb = VerbFactory.getJSON();
//etc
});
I'm using Angular 1.3 I have changed my code to use Controller as from using $scope.
I have a url:
http://localhost:3640/api/v1/topics
That gets the following json:
[
{
topicId: 17,
title: "This is another BRAND SPANKIN new topic",
body: "This is a message in the body of another topic ftw!",
created: "2014-11-27T05:37:49.993",
replies = null
},
{
topicId: 18,
title: "This is another BRAND new topic",
body: "This is a message in the body of a topic wow!",
created: "2014-11-27T05:37:49.993",
replies = null
}
]
I also have a page called index-home.js
var app = angular.module("myApp", []);
app.controller("homeIndexController", ["$http", function ($http) {
var msg = this;
msg.dataCount = 0;
msg.replies = [];
$http.get("/api/v1/topics?includeReplies=true")
.success(function(data) {
//Success
msg.replies = data;
})
.error(function() {
//Error
alert('error/failed');
});
}]);
On my page I use the following bindings:
<div id="ngController" ng-controller="homeIndexController as hic">
...
<h3>Message count: {{hic.dataCount}}</h3>
...
<div class="message row" data-ng-repeat="i in hic.data">
<div class="title">{{i.title}}</div>
<div class="date">{{i.created}}</div>
<div class="contents">{{i.body}}</div>
</div>
I know that the url in the $http is working because I tried it by itself in the browser and fiddler and it returned the json. But when I use it in my angular app I get the .error result (which is a alert saying FAIL.
I have tried removing the http://localhost:3640 and just using /api/v1/topics when I do that, I don't get the error result anymore. I know my controller is working and binding to the page because I get back 0 for dataCount.
What am I doing wrong in the $http method? Is my syntax wrong?
The error is in your ng-repeat attribute. You do not have a data variable in your scope.
Change hic.data to hic.replies and it will work.
<div id="ngController" ng-controller="homeIndexController as hic">
...
<h3>Message count: {{hic.dataCount}}</h3>
...
<div class="message row" data-ng-repeat="i in hic.replies">
<div class="title">{{i.title}}</div>
<div class="date">{{i.created}}</div>
<div class="contents">{{i.body}}</div>
</div>
Alright dude, this is a real rookie mistake, look at your controller:
app.controller("homeIndexController", ["$http", function ($http) {
var msg = this;
msg.dataCount = 2;
msg.replies = [];
$http.get("/api/v1/topics")
.success(function(data) {
//Success
msg.replies = data;
})
.error(function() {
//Error
alert('eror/failed');
});
}])
You are setting this to msg, then setting msg.replies to equal data if success.
This is ok.
Your problem then comes in your ng-repeat when you say:
<div data-ng-repeat="i in hic.data">
hic.data doesn't exist. data was the item returned from the .success(function()) of the $http.get. You then take that data and assign it to msg.replies. So your ng-repeat="" should look like this:
<div data-ng-repeat="i in hic.replies">
Understand? This is basic stuff... I, uh I mean you should feel really silly.
I'm having some problems figuring out why this simple Knockout mapping isn't working. I'm not sure if the returned JSON is invalid or if my mappings are wrong or if it's simply the bindings.
The data structure is a parent Conversation object with an array of Message objects.
On the bindings I'm using foreach: Conversation at the moment because I have this working if I wrap the whole thing a single element array.
My bindings
<div data-bind="foreach: conversation">
<div data-bind="foreach: messages">
<div class="well">
<div data-bind="text: sender_name"></div>
<div data-bind="text: subject"></div>
<div data-bind="text: body"></div>
<div data-bind="text: updated_at"></div>
</div>
</div>
</div>
My ViewModel, faked JSON and mappings
// Sample JSON to return for initialization; 2 second delay
var conversationData = {
json: $.toJSON(
{"id":8,"subject":"Hello JB! Email two!",
"updated_at":"Sep 27",
"originator":"James Pablo",
"count_messages":"(2)",
"messages":[{"subject":"RE: Hello JB! Email two!",
"body":"Thanks for the message!",
"sender_name":"Joe Flynn","updated_at":"Sep 27"},
{"subject":"Hello JB! Email two!",
"body":"Body text",
"sender_name":"James Pablo",
"updated_at":"Sep 27"}
]
}
),
delay: 1
}
function Conversation(data) {
ko.mapping.fromJS(data, {}, this);
}
function Message(data) {
ko.mapping.fromJS(data, {}, this);
}
var map = {
create: function(options) {
return new Conversation(options.data);
},
messages: function(options) {
return new Message(options.data);
}
}
var ViewModel = function() {
var self = this;
self.conversation = ko.observable();
// Use JSFiddle echo to simulate an AJAX service
(function() {
$.ajax({ url:"/echo/json/", data:conversationData, type:"POST",
success:function(data)
{
// Map the returned JSON to the View Model
ko.mapping.fromJS(data, map, self.conversation);
}
});
})();
console.log(self.conversation());
};
ko.applyBindings(new ViewModel());
This JSFiddle works when I'm returning the JSON data wrapped in a single element array.
If I remove the array wrapper from the JSON in this JSFiddle (which is what I want as I only want to render a single conversation) then I can't get it to work. Any ideas?
Create function only works on arrays.
Try this
http://jsfiddle.net/C46pU/2/
Removed Convension from map literal and did
self.conversation(new Conversation(data));