React JSX and Django reverse URL - django

I'm trying to build some menu using React and need some Django reverse urls in this menu. Is it possible to get django url tag inside JSX? How can this be used?
render: function() {
return <div>
<ul className={"myClassName"}>
<li>Menu item</li>
</ul>
</div>;
}

You could create a script tag in your page to inject the values from Django into an array.
<script>
var menuItems = [
{title: 'Menu Item', url: '{% url "my_reverse_url" %}'},
{title: 'Another Item', url: '{% url "another_reverse_url" %}'},
];
</script>
You could then pass the array into the menu through a property.
<MyMenu items={menuItems}></MyMenu>
Then loop over it to create the list items in your render method.
render: function(){
var createItem = function(itemText) {
return <li>{itemText}</li>;
};
return <ul>{this.props.items.map(createItem)}</ul>;
}
This will keep your component decoupled and reusable because the logic for creating the data and the logic for displaying the list items is kept separate.

Related

Django Ajax Dropdown Select2 not return data

There is a dropdown form that I created with ajax. The form works without using the Select2 tag and returns data. But when I enter the select2 tag, it does not show the detail that should be displayed according to the selection.
I use select2 for all select fields in the system. That's why I defined the select2 tag on my layout template like this.
<script>
$('.select').select2({
allowClear: true
});
</script>
Here is my ajax code :
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
$("#id_worksite_id").change(function () {
const url = $("#subunitForm").attr("data-subunit-url");
const worksiteId = $(this).val();
$.ajax({
url: url,
data: {
'worksite_id': worksiteId
},
success: function (data) {
$("#id_upper_subunit_id").html(data);
}
});
});
Thank you for your help, best regards

Django: how to get a javascript value from template to view?

I am currently using Django framework.
I would like to get the value of a javascript value wrote in an html file.
I would like to be able to display it in my view file
Here is my html file from the folder templates:
<script>
var toto = "javascript";
document.write(toto)
</script>
This is my view file:
def javascript(request):
# print the javascript value here
return render(request, "rh/javascript.html")
Thank you for your help !
You have to consider that your script runs on the client-site whereas the view function runs on the server-side. This is one main challenge when it comes to shifting variables from one end to the other.
To make a long story short:
You will have to make a http request from the client-site (for example using jQuery AJAX) to call the view. Then you can pass the variable via AJAX to the view function and use it for further logic.
Example:
your.html
<script type="text/javascript">
// A CSRF token is required when making post requests in Django
// To be used for making AJAX requests in script.js
window.CSRF_TOKEN = "{{ csrf_token }}";
</script>
<div id="variable">Variable</div>
javascript
(function($) {
// trigger the logic on click of the container
$('#variable').on('click', function() {
// assign variable
var variable_for_view = $(this).html();
// make http request using AJAX
$.ajax({
type: 'post',
url: '/your_url/', // this is the mapping between the url and view
data: {
'variable': variable, // ! here is the magic, your variable gets transmitted to the server
'csrfmiddlewaretoken': window.CSRF_TOKEN
},
success: function(data) {
print(sliced_variable)
},
});
});
}(jQuery));
views.py
def your_view(request):
# Assign variable from AJAX request
variable = request.POST.get('variable')
print(variable)
variable.slice(3)
context = {
'sliced_variable': variable
}
return render(request, 'your.html', context)

Populating nested underscore templates in Backbone.js

I am attempting to create an html page from a complex JSON object. I have already successfully parsed the JSON object into a Collection of Models, Where each Model has a collection of another Model etc..
I therefore have nested views to cater for this.
To create my html page, I have two templates like the following:
<script type="text/template" id="template1">
<h1><%=heading1%></h1>
<h2><%=heading2%></h2>
<ul id="template2-list"></ul>
</script>
<script type="text/template" id='template2'>
<p class = "heading"><%-otherheading%></p>
<div class="content" id="tab">
.....
</div>
</script>
As you can see, I have a template (template1) that contains a list of template2. How would I go about populating these templates from my Backbone nested views?
This is what I have tried:
var CollectionView = Backbone.View.extend({
type: "CollectionView", //For debugging purposes
el: "#container",
initialize: function () {
},
render: function () {
_.each(this.model.models, this.process, this);
return this;
},
process: function(obj)
{
var childItemView = new View1({model: obj});
childItemView.render();
this.$el.append(childItemView.el); //This works fine since I only have one Model in the highest level collection
}
})
var View1 = Backbone.View.extend({
type: "View1",
template: _.template($("#template1").html()),
tagName: "div",
className: "tableRow",
initialize:function () {
this.model.on("change", this.modelChanged, this);
},
render: function () {
var outputHtml = this.template(this.model.toJSON());
this.$el.html(outputHtml);
this.model.get('nestedModel').each(this.process, this);
return this;
},
process: function(obj) {
var childItemView2 = new View2({model: obj});
childItemView2.render();
childItemView2.el = '#template2-list';
$(this.el).append(childItemView2.el); //This still results in template2 being placed after the entire template 1
},
modelChanged: function(model, changes) {
console.log("modelChanged: " + this.model.get('title'));
}
});
If it's just populating underscore, then you should convert the collection to json(including the submodels collections), and you can add a for loop inside of the template. <% for(var x... %>.
The other option is, to use a library like marionette which has a composite view which can hold collection views, you can see an example for a treeView here: http://lostechies.com/derickbailey/2012/04/05/composite-views-tree-structures-tables-and-more/
it basically shows how to render collections inside collections.
There are lots of ways to do this.
Template inside template
Pass the entire collection and do all recursive iteration logic in the template itself by calling the child template inside parent template itself. Only one view is involved.
<script type="text/template" id="template1">
<h1><%=heading1%></h1>
<h2><%=heading2%></h2>
<ul id="template2-list">
<!-- Your iteration logic goes here -->
<%= _.template($("#template2").html())({model: model}) %>
</ul>
</script>
<script type="text/template" id='template2'>
<p class = "heading"><%-otherheading%></p>
<div class="content" id="tab"></div>
</script>
Better way is:
In the collection view, create a child view instance(you have done that)
Do the recursive iteration logic to read the collection models in the collection view(parentview) and call the child view to render the child collections.
If you want a complete solution, create a fiddle with json and html. Will help you to make it work.
I realised my mistake. Not sure if this is entirely correct, but I rendered the parent view first, then found the new list element (template2-list) and appended the rendered child view to that.
i.e.
render: function () {
var outputHtml = ...
this.$el.html(outputHtml); //render parent view
this.model.get('nestedModel').each(this.process, this);
...
},
process: function(obj) {
var childItemView2 = new View2({model: obj});
childItemView2.render();
this.$('#template2-list').append(childItemView2.el);
},
Thanks for all the help!

Backbone: dynamic views hierarchy with templates

I have three different view templates: "post", "comment", "add new comment". The main template is "post". I need to find out how to place "comments" and "add new comment" templates into theyr divs in the "post" template. Or any other methods to make this structure:
- post
- comments
- add new post form
- post
...
It is similar to facebook wall
Javascript for Backbone:
// Post View
var PostView = Backbone.View.extend({
template: $("#post").html(),
...
render: function () {
var tmpl = _.template(this.template);
var thisPost = this.model.toJSON();
this.$el.html(tmpl(thisPost));
}
});
var postView = new PostView();
postView.render();
// Comments List
var CommentsListView = Backbone.View.extend({
el: '#comments', // how to place it to #comments div in "post" template? This line doesn't work
...
addNewCommentForm: function (post_id) {
var tmpl = _.template($("#addCommentTemplate").html());
this.$('#addNewComment').append(tmpl()); // How to place it to #addNewComment div in "post" template? This line doesn't work
}
});
HTML:
<script id="post" type="text/template">
<%= text %>
<div id='comments'>...</div>
<div id='addNewComment'>...</div>
</script>
There are a number of things wrong with your code. The first being that you aren't actually putting the PostView.el into the DOM. Through PostView.render(), you are populating PostView.$el and subsequently PostView.el, but you're not actually putting it into the page (DOM). Additionally, by setting the el on CommentsListView, you're not really doing anything there. If you wanted to set the el to an existing element, then you would do something like this: el: $('#comments'). Or if you want to render the CommentsListView dynamically and inject it into the DOM, then you would want to just make the element have an id of 'comments' by doing defining the id property like so: id: 'comments'. Those are just the two most obvious problems with the code. I got a semi-working example running here: http://codepen.io/jayd3e/pen/hAEDv.

How to get a backbone view to 'start' (run) on a page?

I am just getting started with Backbone, and I have set up in a sample app the backbone dependencies (backbone, underscore, json2), and I started writing some backbone models, views, and such for my app.
My question is: suppose a user navigates to a page in my app. How does this page then initialize/call a backbone view? I was under the impression that I am supposed to include this kind of jQuery/js on the page that is loaded:
$(document).ready(function(){
window.app = new SampleApp.Views.Articles.ShowView();
new SampleApp.Routers.RootRouter();
Backbone.history.start();
});
And then I thought the Articles ShowView would run:
$(document).ready(function(){
SampleApp.Views.Articles || (SampleApp.Views.Articles = {});
window.SampleApp.Views.Articles.ShowView = Backbone.View.extend({
el: ".container",
events: {
'click .overlay': 'test'
},
initialize: function(){
//eg: this.model.bind('change', this.render, this)
},
render: function(){
$(".container").html('');
alert('got here');
},
test: function(){
alert('clicked a picture');
}
})
});
However, when I load the page, I don't get any of the functionality specified in my ShowView. (no alerts etc..). I realize that 'ShowView' is a misnomer, as it doesn't actually do anything yet. But if it is truly being called, then shouldn't these alerts run?
FYI I think I included all the files for backbone correctly:
<script src="{{ STATIC_URL }}js/underscore.js"></script>
<script src="{{ STATIC_URL }}js/json2.js"></script>
<script src="{{ STATIC_URL }}js/backbone.js"></script>
{# Models #}
<script src="{{STATIC_URL}}js/backbone/models/article.js"></script>
{# Views #}
<script src="{{STATIC_URL}}js/backbone/views/articles/show.js"></script>
{# Routers #}
<script src="{{STATIC_URL}}js/backbone/routers/root.js"></script>
In your example, you need something that invokes render on the ShowView instance. This can either be the responsibility of a route in your router, or you can just do it in the document ready handler that creates your view.
window.app = new SampleApp.Views.Articles.ShowView();
window.app.render();