angular ng-repeat to always show even on empty object - angularjs

Hi I want to post item to server, and with each successful addition, automatically add it to DOM with ng-repeat
<div class="" ng-repeat="book in books" >
<div id="eachBook">{{book.title}}</div>
</div>
to POST the data and also to upload an image file, I use Jquery ajax, and $state.go(".") to reload the current page:
var fd = new FormData();
fd.append("file", bookImage);
$http({
method: 'POST',
url: "/someurl,
data: fd,
headers: {
'Content-Type': undefined
}
}).success(function(Image){
var book_obj = {
bookTitle: bookTitle,
bookImage: Image._id
};
$http.post("url to owner book", book_obj)
.success(function(data){
$scope.bookImage = data.bookImage;
$timeout(function(){
alert("success", "successfully added your book");
$state.transitionTo('book', {}, { reload: true });
},2000);
})
})
The problem is with first addition, the DOM is still empty, and even though I use $state to reload the page, it still not working for the first addition. In the end I need to refresh the page manually by clicking refresh.
after the first addition, it works fine. With each book added, it automatically added to DOM..
Any idea how to automatically start the first one without manually rendering the page? using $timeout to delay the refresh has no effect.

Is it not just a simple post to list on success?
var app = angular.module('myApp', []);
app.controller('bookCtrl', function($scope, $http, $timeout) {
$scope.init = function(){
$scope.title = 'initial book?'
postBook();
};
$scope.books = [];
$scope.post = function() {
postBook();
};
function postBook(){
if (!$scope.title) return;
// timeout to simulate server post
$timeout(function() {
$scope.books.push({title:$scope.title});
$scope.title = null;
}, 1000);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="bookCtrl" ng-init="init()">
<div class="" ng-repeat="book in books">
<div class="eachBook">{{book.title}}</div>
</div>
<input type="text" ng-model="title" /><button ng-click="post()">save</button>
</div>
EDIT: Not sure why your DOM isn't ready but how about ng-init to accomplish an initial book post?

Related

html data get from $http GET is not showing properly in Angular js..?

I have defined a controller like this :
app.controller("home", function ($scope, $http, $common) {
$http({
method: "GET",
url: '/posts/loadData'
}).then(function (response) {
//console.clear()
if (typeof response.data.posts != 'undefined') {
console.log(response.data.posts);
$scope.posts = $common.arrangePosts(response.data.posts);
}
});
})
and a service to arrange data :
app.service('$common', function ($timeout, $sce, $httpParamSerializerJQLike) {
var that = this;
this.arrangePosts = function (rawPosts) {
var posts = [];
$.each(rawPosts, function (key, value) {
posts.push({
postId: value.postId,
postLink: '/post/' + that.cleanString(value.title) + '/' + value.postId,
title: value.title,
summary: $sce.trustAsHtml(value.summary)
});
});
return posts;
}
});
using values in html like this :
<div class="widget fullwidth post-single">
<h4 class="widget-title">Latest</h4>
<div class="widget-content">
<ul>
<li ng-repeat="post in posts">
<h4 class="list-title">{{post.title}}</h4>
{{post.summary}}
</li>
</ul>
</div>
</div>
Data coming from server in JSON form :
Object { postId="4", title="asdf", summary="<p>asdf</p>"}
but all the html tags are printing on my page as it is (like a text) in summary.
In many SO posts people suggested to use $sce.trustAsHtml but its not working for me. Please suggest anyway to solve my problem.
Any help will be appreciated..!!
have you tried this?
<div ng-bind-html='post.summary'></div>
You could solve this over a directive. Did you know, that you can use JQuery Lite inside AngularJS to manipulate the DOM?
Here a quick example:
angular.module("PostsDirective",[])
.directive("posts", function($sce){
return {
link: function($scope, $element, $attrs){
//the HTML you want to show
var post = "<div>hello world</div>";
var posts = [post,post,post,post];
//iterating through the list (_.each is a function from underscore.js)
_.each(posts, function(element){
//if you want to save the trusted html string in a var you can do this with getTrustedHtml
//see the docs
var safeHtml = $sce.getTrustedHtml($sce.trustAsHtml(element));
//and here you can use JQuery Lite. It appends the html string to the DOM
//$element refers to the directive element in the DOM
$element.append(safeHtml);
});
}
};
});
And the html
<posts></posts>
This also pretty nice for the readability for your HTML code. And you can use it everywhere on your page.
BTW:
As i can see, you get the HTML elements directly from a REST-Service. Why don't you get just the data and insert it into the ng-repeat? If you transfer all the HTML you get a pretty high overhead if you have loads of data.

AngularJs and two Controllers

I am writing an application that is running AngularJs & Bootstrap on the frontend - and using angularjs' $http to make calls to an API...I have two controllers within one app -- the first controller displays the person's name and the second controller displays a list of performances that this person has seen...
<html lang="en" ng-app="myapp">
...
<div class="panel-body" ng-controller="Ctrl">
<div class="row">
<div class="col-sm-3" style="height: 50px;">
<div class="well well-sm">
First Name:
{{ user.fname || "empty" }}
</div>
</div>
<div class="col-sm-3" style="height: 50px;">
<div class="well well-sm">
Last Name:
{{ user.lname || "empty" }}
</div>
</div>
</div>
</div>
<div class="list-group" ng-controller="Ctrl2">
<div ng-repeat="obj in performances" >
<div class="list-group-item">
<h4 class="list-group-item-heading">
<span class="badge">
{{$index+1}}</span> {{ obj["Perf_name"] || "empty" }}</h4>
<p class="list-group-item-text">
Date: {{ obj["Perf_dt"] || "empty" }}<br />
Theater: {{ obj["Theater"] || "empty" }}<br />
</p>
</div>
</div>
</div>
...
</html>
In the JS file I have the following code
Declare my variables and module
var app = angular.module("myapp", ["xeditable"]);
var q = getUrlParameter("q"); // get the query param
var baseurl = "https://some.domain/service/getCRM";
var baseurl2 = "https://some.domain/service/getPerformances";
Create a service to be used by both controllers
app.service('crmService', function () {
this.id = 0;
this.getID = function () { return this.id };
this.setID = function (newid) { this.id = newid; };
});
Define Controller #1
app.controller('Ctrl', function ($scope, $http, crmService) {
$http({
method: 'GET',
url: baseurl,
respondType: 'json',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
params: {
phone_no: q
}
}).then(function successCallback(response) {
$scope.user = {
fname: response.data[0]["FirstName"],
lname: response.data[0]["LastName"]
}
crmService.setID(response.data[0]["CRM_ID"]);
console.log("*** OUTPUT LINE 1: " + crmService.getID());
}, function errorCallback(response) {
console.log("**ERROR");
console.log(response);
});
});
Define Controller #2
app.controller('Ctrl2', function ($scope, $http, crmService) {
console.log("*** OUTPUT LINE 2: " + crmService.getID());
var promise = $http.get(baseurl2 + "?crm_id=" + crmService.getID());
promise.then(
function (response) {
$scope.performances = response.data;
});
});
Console output
*** OUTPUT LINE 2: 0
*** OUTPUT LINE 1: 123456
Questions:
Why is the second controller outputting before the first, I assume it is because AngularJs by default executes its code asynchronously, and if that's the case, why did the "promise" not work?
What I need to happen is, I make my GET call in the first controller block and assign the customer ID using my service...I then go on to the second controller block and using the customer ID, from my service (which was set within the first controller block) - get the customer's performances
So I have to first controller working fine, but the second controller keeps thinking that the customer ID is 0 - when it should be 123456
What am I missing?
FYI: when I hard code an ID for the second controller to use, I get actual performance records back - so I know everything will work once I figure out how to share values between my controllers
Why is the second controller outputting before the first
Because the second controller logs the ID as soon as it's instanciated, whereas the first one logs it once it has received, asynchronously, a response to an HTTP request. The promise did work, since the output is logged in the console.
What I need to happen is, I make my GET call in the first controller block and assign the customer ID using my service...I then go on to the second controller block and using the customer ID, from my service
You're doing your job more complex than it should be: using a single controller would be much easier here, since the model of the second one depends on what the first one does.
You could broadcast an event from the first controller to signal that the ID has been set, and listen to the event in the second one to get the data at tis time.
app.controller('Ctrl', function ($scope, $http, $rootScope, crmService) {
$http({
...
}).then(function successCallback(response) {
...
crmService.setID(response.data[0]["CRM_ID"]);
console.log("*** OUTPUT LINE 1: " + crmService.getID());
$rootScope.$broadcast('crmIdChanged');
};
});
app.controller('Ctrl2', function ($scope, $http, crmService) {
function getPerformances() {
var id = crmService.getID();
if (id != 0) {
var promise = $http.get(baseurl2 + "?crm_id=" + crmService.getID());
promise.then(
function (response) {
$scope.performances = response.data;
});
}
}
getPerformances();
$scope.$on('crmIdChanged', getPerformances);
});
You could even broadcast the even from the service itself.

Why is angular not rerendering?

When I call $scope.remove in the html it calls the rerender function then automatically updates the data in the html.
When I call $scope.post it calls the rerender function and logs the new data. However, it doesn't automatically rerender the html. I have to refresh the page in order to see the up to date data.
I've looked into using $apply but I'm puzzled how it's updating for remove but not post.
Controller:
var updateData = function (resp){
$scope.data = resp.data;
console.log($scope.data);
}
$scope.getEntries = function (){
return $http({
method: 'GET',
url: '/allEntries'
}).then(updateData)
};
$scope.post = function (){
return $http({
method: 'POST',
url: '/newEntry',
data: $scope.entry
}).then(function (resp){
$scope.getEntries();
})
};
$scope.remove = function (opp){
return $http({
method: 'POST',
url: '/deleteEntry',
data: opp
}).then(function (){
$scope.getEntries();
})
}
I'm thinking it might be something to do with having the functions called in different html files but since they both have the same controller I would think that wouldn't be the case.
<html>
<body ng-app = "app">
<div ng-controller = "controller">
<form ng-submit = "post()">
<input type="submit" value="Submit">
</form>
</div>
</body>
</html>`
<html>
<body ng-app = "app">
<div ng-controller = "controller">
<ul>
<li ng-repeat = "job in data" ><input type = "button" ng-click = "remove(opp)" value="Delete"></li>
</ul>
</div>
</body>
</html>`
Indeed, you have two different sections, each with their own controller, and thus each with their own scope:
one which displays the list of items
one which diesn't display anything
You're posting from the section which doesn't display anything, so it refreshes the list in the scope of that section, which still doesn't display anything.
So, in short, both sections don't have the same controller. They have different controller instances, and those instances happen to have the same type. But they're still completely independant from each other.
And actually, re-reading your question, it's actually worse than that. It seems you have two browser tabs or frames opened. You are posting from one of the tabs, and hope that the other one will refresh automatically. That won't happen: the two tabs are completely independant applications.

Why angularjs controller is not called when i click the button again?

Hi i have a webpage like this,
left side has button,
right side is the area for ng-view (in my case, several checkboxes and submit button)
When i click the button, it'll
1. using the route provider, it'll reach its controller and template URL.
2. The controller will query some info from back end side (node.js)
3. The info above will be used by template URL to display initial checkbox options.
Now this procedure works fine for the 1st time. But when i click the button again, i was hoping it'll call its controller again, but from debugger, seems nothing happened, controller is not called.
So very confused, why is this please ???
in the server side,
app.get('/2getMyDiagValue', function(req, res)
{
console.log("get my diag");
var v1=0, v2=0;
var shellCmd = "... some executable ... ";
exec(shellCmd, function(error, stdout, stderr) {
if(error) {
console.log("Error running getting sid");
} else {
// get v1 and v2 from stdout
}
res.json( {"mystuff1":v1, "mystuff2":v2} );
});
app.post('/2setMyDiagValue', function(req, res)
{
// get the checkbox options from webpage,
// and save them in the backend
}
in the client side,
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.when('/5MyDiag', {
templateUrl: 'partials/MyDiag.html',
controller: 'MyDiagController'
});
}
]);
app.controller('myDiagController', function($scope, $http, $routeParams, QueryMyService) {
// using http.get() to get existing my setting from server side
QueryMyService.getInfoFromUrl7('/2getMyDiagValue').then(function(result) {
$scope.formData = result.formDataObjects;
}, function(error) {
alert("Error");
} );
$scope.submitForm = function() {
console.log("posting form data ...");
$http.post("/2setMyDiagValue",
JSON.stringify($scope.formData)).success(function(){} );
};
});
app.factory('QueryMyService', function($http, $q, $location) {
var factory = {};
var browserProtocol = 'http';
var address = 'localhost';
var server = browserProtocol + '://' + address;
//////////////////////////////////////////////////////////
factory.getInfoFromUrl7 = function(myUrl) {
var deferred = $q.defer();
$http.get(myUrl).success(function(data) {
deferred.resolve(data);
}).error(function(){
deferred.reject();
});
return deferred.promise;
}
return factory;
}
checkbox webpage itself: MyDiag.html
<form ng-submit="submitForm()" ng-controller="myDiagController">
<div class="control-group" style="color:black">
<label>My Checkbox</label>
<div class="checkbox">
<label class="checbox-inline" >
<input class="big-checkbox" type="checkbox" ng-model="formData.myStuff1"
ng-true-value="1" ng-false-value="0" ng-checked="formData.myStuff1 == 1">
<h4>Message 1</h4>
<input class="big-checkbox" type="checkbox" ng-model="formData.myStuff2"
ng-true-value="1" ng-false-value="0" ng-checked="formData.myStuff2 == 1">
<h4>Message 2</h4>
</label>
</div>
<br>
<input class="btn-primary" type="submit">
</form>
index.html
<div class="container">
<a class="btn btn-md btn-info custom-btn" ng-href="#/5MyDiag">Diagnostics</a>
</div>
Since i need to remove company names in the variable, there might be mismatch, but idea is the same. Thank you for your help.
Talked with guru, it's supposed to be so, if angular feels no change to the web GUI, e.g. in my case, i clicked the same button twice, it won't call the route provider again for the 2nd click.
If you knew this concept, you don't need to read my code to answer this question.
Wish i can get the 4 points back.

How to convert jquery to Angular in $(".video:last").after(data);

$(".video:last").after(data);
in ng-repeat Angular
$http({
method : "GET",
url : base_url + 'video/get_video_list',
params: {last_video_id : ID}
}).success(function(data){
$scope.videos = data;
});//End http
Please Help Me T_T
So assuming you are finding the last DOM element with a class of 'videos', $(".video:last"), and then inserting the content from your data variable after that, .after(data); and also based on you bolding ng-repeat I'm assuming you are using an ng-repeat for $scope.videos in your partial.... you can access the last item in an ng-repeat via $last.
Here is a list of other ng-repeat variables
if you set your data equal to a $scope value (i.e. $scope.myData) you can interpolate that into your last ng-repeat item. i.e:
<div ng-if="$last">{{myData}}</div>
But to be honest I'm not sure what you're asking...
Hope this points you in the right direction.
i try to Infinite Scrolling
http://binarymuse.github.io/ngInfiniteScroll/
i can not show data when scroll
every function loadMore() show in ng-repeat replace in old value T_T
i hope use Angular for Good Filter Sort Data in Infinite-scroll
thank for Answer me..
<script type="text/javascript">
var app = angular.module('app', ['infinite-scroll']);
app.controller('DemoController', function($scope, $http) {
var base_url = '<?php echo site_url(); ?>';
$scope.loading = true;
var ID = $(".video_box:last").attr("id");
console.log('Value Id ///////////');
console.log(ID);
console.log('//////////////// load more ////////////');
$http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
$http({
method : "GET",
url : base_url + 'video/get_video_list',
params: {last_video_id : ID}
}).success(function(data){
$scope.videos = data;
console.log('//////////////// success Data ////////////');
$scope.loading = false;
});//End http
};//End loadMore
});//End Controller
// we create a simple directive to modify behavior of <ul>
app.directive("whenScrolled", function(){
console.log('whenscroll--------------');
return{
restrict: 'A',
link: function(scope, elem, attrs){
// we get a list of elements of size 1 and need the first element
raw = elem[0];
// we load more elements when scrolled past a limit
elem.bind("scroll", function(){
if(raw.scrollTop+raw.offsetHeight+5 >= raw.scrollHeight){
scope.loading = true;
console.log('whenscroll--------------');
// we can give any function which loads more elements into the list
scope.$apply(attrs.whenScrolled);
}
});
}
}
});
</script>
<div ng-app='app' ng-controller='DemoController'>
<div infinite-scroll='loadMore()' infinite-scroll-distance='2' >
<div ng-repeat="video in videos" >
<div id='{{video.id}}' class='video_box'>
<li class='block'>
<a href='<? echo base_url();?>video/view/{{video.id}}' class='video-thumbnail' >
<img src="http://img.youtube.com/vi/{{video.url}}/1.jpg" alt='{{video.title}}'/>
<div ng-if="$last" ><h2>{{video.title}}</h2></div>
</a>
</li>
</div>
</div><!-- End video in videos -->
<div data-ng-show='loading'>Loading</div>
</div><!--End infinite-scroll-->
</div><!--End App -->

Resources