Included template getting loaded before model is available from controller - Angular - javascript

I have created a basic tool using vanilla javascript/html/css to perform certain functions across all emails associated with the business. To maintain the code base simplicity, i have started to porting the application using angularJS, creating modules/controllers etc. However, i got stuck with below situation. It looks like from the logs that my included html template gets called before data is ready from the controller.
I am placing an ajax call from the server which roughly takes ~1 sec. But by the time, I guess Angular executes the included template and because of no model availability, it renders nothing on the application side.
A look into my code:
index.html
<div class="tab-pane active fade in" id="results">
<section ng-controller = "messageSelectionController" ng-include src="'templates/messageSelectionTemplate.html'"></section>
</div>
messageSelectionController.js
app.controller('messageSelectionController',function($scope,$log){
//Generic ajax call
var makeRequest = function(paramObj,successCallback,errorCallBack,url,type){
$.ajax({
method : type ? type : "GET",
url : url ? url : "https://xx.xx.xx/xx/xx",
data : paramObj,
xhrFields : { withCredentials : true }
}).then(successCallback,errorCallBack);
};
var messageSelectionSuccessHandler = function(data){
$scope.messageselectionlist = JSON.parse(data).response.docs;
$log.info($scope.messageselectionlist);
};
var messageSelectionErrorHandler = function(data){
$log.info(data.responseText);
};
var data = {
q : "",
fq:[
'View:xx',
'Platform:xx'
],
start : 0,
rows : 9999
};
makeRequest(data, messageSelectionSuccessHandler,messageSelectionErrorHandler);
});
messageSelectionTemplate.html
<ul>
<li ng-repeat="item in messageselectionlist">
<article class="">
<span class="label label-success">MessageSelection</span>
<a> "Platform : {{item.Platform}} | View : {{item.View}} | Locale : {{item.Locales[0]}}"
<i class = "ocon-flag-{{item.Locales[0] | lowercase }}"></i>
</a>
<span class = "label label-inverse">{{item.Description}}</span>
</article>
</li>
</ul>
I tried to put logs to see when the messageSelectionTemplate is loaded, using below code:
$scope.$on('$includeContentLoaded', function(event, target){
console.log(event); //this $includeContentLoaded event object
console.log(target); //path to the included resource, 'snippet.html' in this case
});
and here's the logs:
-----templates/messageSelectionTemplate.html angular.js:13424
-----Array[654]
Can someone let me know how to defer the included template loading until the modal for template is not available. Thanks!

Related

Django: Writing JavaScript inside template vs loading it

I am using JavaScript to add comment without refreshing the page. When I am using JavaScript inside the template it is working perfectly fine but if I am writing the JavaScript to a file and loading the file inside the template then it is not displaying the name of the person who wrote the comment (It is displaying the comment fine). Below is the JavaScript I used inside the template:
function create_comment(event,div_id,form_id,commentinsert_id) {
event.preventDefault();
var text_id = '#'.concat(div_id,' ','#comment-text')
var slug_id = '#'.concat(div_id,' ','#post_slug')
var appenddiv_id = '#'.concat(div_id)
comment_count ++;
var divcommentinsert_id = 'inserted_comment-'.concat(comment_count.toString())
$.ajax({
url : "create_comment/", // the endpoint
type : "POST", // http method
data : { text : $(text_id).val(), post_slug: $(slug_id).val(),},
// handle a successful response
success : function(json) {
div.innerHTML = `
<div id = `+divcommentinsert_id+` class="card-footer">
<div class="row">
<div>
<img src="{{user.profile.profile_picture.url}}" alt="" width="40" height="40">
</div>
<div class="col-md-8">
<b style="color:rgb(240, 0, 0);"> {{user.first_name}} {{user.last_name}}</b>
<br>
`+json.text+`
<a onClick="edit_comment('`+json.slug+`','`+divcommentinsert_id+`','`+json.text+`')"><i class="fa fa-edit"></i></a>
<a onClick="delete_comment('`+json.slug+`','`+divcommentinsert_id+`')"><i class="fa fa-trash-o"></i></a>
</div>
</div>
</div>`;
document.getElementById(commentinsert_id).appendChild(div);
document.getElementById(form_id).reset();
},
// handle a non-successful response
error : function(xhr,errmsg,err) {
$('#results').html("<div class='alert-box alert radius' data-alert>Oops! We have encountered an error: "+errmsg+
" <a href='#' class='close'>×</a></div>"); // add the error to the dom
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
};
In the above code <b style="color:rgb(240, 0, 0);"> {{user.first_name}} {{user.last_name}}</b> is used to display the name. It is displaying name of the person who added the comment but when I copy the same function to comments.js file and load the file like <script src="{% static 'scripts/comments.js' %}"></script> then its not displaying the name instead it is displaying {{user.first_name}} {{user.last_name}}. I am using this javascript in several pages, I thought it is best to write to file and load the file instead of writing the same script in every page. Can someone help me with this?
{{ dictionary.key }}, etc in a template is how you use variables with the django template engine.
A static javascript file is not a template. It isn't processed by the django template engine.
Put the values you need in your html (through the template engine), access them from JS.
Basic ideas:
Create a JS variable (eg: <script>var user_full_name = "{{ user.user_name }} {{ user.last_name }}"</script>), use user_full_name inside the ajax sucess callback.
Put the values inside some html element (eg: <input type="hidden" id="user_name" value="{{ user.user_name }}">) and get it with JS/jQuery $("#user_name").val().
edit: added missing closing double quote to the user_full_name declaration.

Angular scope not updating when passed in object to function

I have a controller function which is called on double click of an item in an ng repeat:
$scope.likeUpdate = function(update) {
$http.post( $rootScope.apiURL + 'likeupdate', {
update_id : update.data.id,
user_id : $rootScope.currentUser.id
}).success(function(result, response){
update.data.does_like = result[0][0].does_like;
console.log(result[0][0].does_like);
});
}
This, should to me, change on my Ionic app and update on the screen the 'does_like' value.
However, it doesn't.
Here is my ng repeat:
<div ng-repeat="update in updates" class="custom-card">
<div ng-show="{{update.image}}" class="image">
<img on-double-tap="likeUpdate({{update.data.id}})" class="full-image" ng-src="https://s3-eu-west-1.amazonaws.com/images/{{update.image.name}}" imageonload>
</div>
{{ update.data.does_like }}
</div>
On page load, the update.data.does_like correctly shows what I need, and after page refresh will show what It should. But in my code its not updating live on the success callback.
The console log shows the correct output.
P.S I know doing result[0][0] isn't good, shall be working on structure soon.
In order for likeUpdate to change the data.does_like property of the update in question, you should pass the update to it instead of whatever {{update.data.id}} resolves to, ie
<img on-double-tap="likeUpdate(update)" ...
While we're making changes, you should remove the deprecated success method
$scope.likeUpdate = function(update) {
$http.post($rootScope.apiURL + 'likeupdate', {
update_id : update.data.id,
user_id : $rootScope.currentUser.id
}).then(function(response) {
update.data.does_like = response.data[0][0].does_like;
});
};
update is a local variable to the function.
try
$scope.updates = result[0];
But your structure looks off.

Latency when loading html content with FOSJsRoutingBundle and Ajax (route parameter {id})

I am using FOSjSrouting in my symfony2.7 project.
I have this html.twig view code:
<table>
<!--table header code ...etc... -->
<tbody>
{% for currentData in arrayData %}
<tr>
<td>{{ currentData.first_name}}</td>
<td>{{ currentData.last_name}}</td>
<td>{{ currentData.order}}</td>
<td>{{ currentData.category}}</td>
<td>{{ currentData.location}}</td>
<td>{{ currentData.price}}</td>
<td>
<a><button class="btn btn-info btn-xs showDetail" href="{{ path('detailsData', {'idData': currentData.idData }) }}">Show Detail</button></a> <!-- to open dialog tag through Ajax for each lines -->
<button class="btn btn-warning btn-xs">Edit</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- the dialog window to load detail content -->
<dialog id="window"></dialog>
<!-- javascript to open and close dialog window -->
<script>
(function() {
var dialog = document.getElementById('window');
var showButtons = document.getElementsByClassName('showDetail');
var showDialog = function() {
console.log(this);
dialog.show();
dialog.load(Routing.generate('detailsData', {'idData': currentData.idData }) }})
};
var i, len = showButtons.length;
for(i = 0; i < len; ++i) {
showButtons[i].onclick = showDialog;
}
document.getElementById('exit').onclick = function() {
dialog.close();
};
})();
</script>
As you can see, foreach data I want to display, I have a detail button. This detail button refers to another page which displays linked data to the current data I clicked on.
This the route for the detail view (respecting the FOSjSrouting needs):
detailData:
pattern: /manage/order/detail/{idData}
defaults: { _controller: MySpaceMyBundle:MyController:detailData }
requirements:
methods: GET
options:
expose: true
The purpose is to load via Ajax, jQuery, FOSjSrouting the linked datas in the dialog tag with the id="window" to the currentData.idData.
But when I click on the detail button, I have this error (in my browser console):
Uncaught ReferenceError: currentData is not defined
I understand that I need to take care about the {id} parameter of my route.
How can I load the page that the detail button refers to and displays the right linked data through ajax with my current script (at the end of my html code)?
EDIT
I add this code in javascript at the end of my script tag in my html.twig view, it allows me to display the datas I want in my dialog tag:
$('.showDetail').click(function() {
$.ajax({
'url': Routing.generate('detailsData', {'idData': $(this).val()}),
'cache' : false,
'success': function(loadDetail) {
$('#window').html(loadDetail);
}
});
});
The problem occured is that I have a latency to display the dialog tag, and just before displaying the current data I want, the last one I clicked on are displaying before for a few second, and then my current data I want is display later.
Maybe It's a cache problem?
Moreover, the first time I click on the detailButton, the dialog is displaying empty, then after (latency), the data are displaying.
How can I fix these problems?
The problem is, that the variable is not defined in javascript. You have to insert curly brackets to let twig translate the twig variable into the corresponding value like this:
{'idData': {{currentData.idData}} }
Unfortunately therefor it has to be in the for loop as well - so it might be better to safe the value in an data attribute and read it by using javascript.
You could also use the already populated href attribute like this (using jQuery as you said you are doing):
dialog.load($(this).attr('href'))

AngularJS ng-repeat doesn't work on Django powered webpage

I have this 2 parts of AngularJS codes in my Django powered webpage.
Part1
<div class="categoryList">
<ul>
<li data-ng-repeat="cat in categories">
<a>{$ cat.name $}</a>
</li>
</ul>
</div>
Part 2
<li data-ng-repeat="i in range(pictures[currentCat].length)">
<a data-ng-click="changePage(i)">{$ i $}</a>
</li>
This is my controller
$scope.currentPage = 1;
$scope.currentCat = 0;
$.getJSON('categories/',
function(data) {
$scope.categories= data;
});
$scope.pictures=[cat1,cat2,cat3,cat4,cat5]; //cat1..cat5 are some dictionaries like 'categories'
$scope.changePage = function(i){
$scope.currentPage=i;
};
The problem is part 2 works fine while loading the page, But part1 doesn't work until I click on a page number from part2 list and run 'changePage'
This was working fine when my webpage wasn't powered by Django
Update
views.py
def getcategories(request): // /categories/ url runs this
dictionaries = [obj.as_json() for obj in Category.objects.all()]
return HttpResponse(json.dumps(dictionaries), content_type='application/json')
models.py
class Category(models.Model):
name = models.CharField(default='other',max_length=50)
upload_date = models.DateTimeField(default=datetime.now, blank=True)
def as_json(self):
return {
"id": self.id,
"name": self.name
}
As simpe says the output should be {{cat.name}} and {{i}}.
About the "categories", check that the url is working, and then using your browser developer tools see that the right url is invoked.
Also you can use django rest framework and $resource to send your data between front-end and back-end.
I added $scope.$apply() to $.getJSON and now it updates $scope.categories as soon as it gets the results. and everything is working fine now.
$.getJSON('categories/',
function(data) {
$scope.categories= data;
$scope.$apply();
});

Problems with loading a JSON REST-request into Kendo ui list-view

I want to load a a get-request into a kendo-ui listview. I can't figure out why the my site won't show any results. I tried the following code with the exact same data the server returned and it works fine, but i can't get the http-request to work. Here is my js code for the viewmodel:
var eventsDataSource = new kendo.data.DataSource({
transport:{
read: {
url:"https://myurl/incidents",
dataType: "json"
}
},
schema: {
data: function(response){return response;}
},
sort:{field: "id", dir: "desc"}
});
eventsDataSource.read();
var json = eventsDataSource.data().toJSON();
var eventsViewModel ={ events : ko.observableArray(json) };
Here is the view i made which shows the data as intenden when i code the data directly into the dataSource :
<div data-role="view" data-layout="layout" id="event-view" data-ko-model="eventsViewModel">
<ul data-role="listview" data-style="inset" data-type="group">
<li>Ereignisse
<ul data-bind="foreach: events">
<li>
<span style="vertical-align:middle;">
<span data-bind="text: id"></span> - <span data-bind="text: title"></span> (<span data-bind="text: status"></span>)
<br/>
<b data-bind="text:message"></b>
</span>
<div data-bind="if : document">
<a data-role="detailbutton" data-icon="right-open"></a>
</div>
</li>
</ul>
</li>
</ul>
</div>
And finally the data returned from the server:
[{"id":3,"created":1385573907907,"priority":1,"reporter":"Martin","category":"Mähdrescher","type":"S690","title":"Hangausgleich defekt","message":"Mähdrescher umgekippt","status":"offen","client":"Bauer","field":"Kaiserslautern - Kohlbach","scenario":0,"document":true,"positionLatitude":49.405703,"positionLongitude":7.423623},
{"id":1,"created":1385739507907,"priority":3,"reporter":"T670-4","category":"Mähdrescher","type":"T670","title":"Hydraulikdruck unter Minimalwert","message":"Hydraulikdruck unter 200 bar","status":"offen","client":"Meyer","field":"Homburg - Auf der Höh","scenario":0,"document":false,"positionLatitude":49.342852,"positionLongitude":6.824287},
{"id":2,"created":1385656707907,"priority":2,"reporter":"Anna","category":"Traktor","type":"9560RT","title":"Kette gerissen","message":"Linke Kette gerissen","status":"offen","client":"Schulze","field":"Kaiserslautern - Feldstraße","scenario":0,"document":false,"positionLatitude":49.402715,"positionLongitude":7.445082}]
I know it's json, but same origin policy shouldn't be a problem since i want to create a mobile app withour an url. Where do i go wrong. Help is strongly appreciated!
Other than the question of same origin policy, it is not that your HTTP request works but that when you do a read you start reading but this might take some time. So instead of doing a read, try doing a fetch as follow:
var eventsViewModel = null;
eventsDataSource.fetch(function(data) {
var json = data.toJSON();
eventsViewModel = { events : ko.observableArray(json) };
});
Now, the body of the fetch handler is executed when the read is finished and the data is available.

Categories

Resources