django Javascript dropdown - javascript

Am new to programming in Python and Javascript and I have been learning Python for few months now and love it. I have been playing with django which is cool I was wondering how I can make this model work with a Iavascript. I'll like someone to explain as much as the code involved as I just what to have a full understanding of the process from django to Javascript.
I want to dynamically is CarModel.objects.filter(make ='somename') or just 'somename'.
This is a test model am using since its similar to the Javascript I use for tutorial from online (YouTube) the scripts is below as well:
class Make(models.Model):
name = models.CharField(max_length=50,blank=True,null = True)
#so so so so
class CarModel(models.Model):
name = models.CharField(max_length=50,blank=True,null = True)
make = models.ForeignKey(Make,blank=True,null = True)
Now how will you pass say something like this to your Javascript?
class Model(ModelForm):
make = forms.ModelChoiceField(queryset= Model.objects.none(), required=True)
def __init__(self, somemake,*args, **kwargs):
super(Model, self).__init__(*args, **kwargs)
self.fields['property'].queryset = Model.objects.filter(make = somemake)
class Meta:
model = Model
exclude= ('make')
<script type="text/javascript">
function populate(s1,s2){
var s1 = document.getElementById(s1);
var s2 = document.getElementById(s2);
s2.innerHTML = "";
if(s1.value == "Chevy"){var optionArray = ["|","camaro|Camaro","corvette|Corvette","impala|Impala"];
}
else if(s1.value == "Dodge"){
var optionArray = ["|","avenger|Avenger","challenger|Challenger","charger|Charger"];
} else if(s1.value == "Ford"){
var optionArray = ["|","mustang|Mustang","shelby|Shelby"];
}
for(var option in optionArray){
var pair = optionArray[option].split("|");
var newOption = document.createElement("option");
newOption.value = pair[0];
newOption.innerHTML = pair[1];
s2.options.add(newOption);
}
}
</script>
and html here
Choose Car Make:
<select id="slct1" name="slct1" onchange="populate(this.id,'slct2')">
<option value=""></option>
<option value="Chevy">Chevy</option>
<option value="Dodge">Dodge</option>
<option value="Ford">Ford</option>
</select>
Choose Car Model:
<select id="slct2" name="slct2"></select>

If you want to do in JS, this is how I would solve the problem.
First create a template that contains the following for the 2 select lists.
<html>
<head>
<script>
var json = {
"Chevy": ["chev1", "chev2", "chev3"],
"Dodge": ["dodge1", "dodge2", "dodge3"],
"Ford": ["ford1", "ford2", "ford3"]
};
function carMake () {
select = document.getElementById('slct1');
select.options.length = 0;
for(make in json) {
select.options[select.options.length] = new Option(make, make);
}
}
function carModel(sel) {
var car_make = sel.options[sel.selectedIndex].value
select = document.getElementById('slct2');
select.options.length = 0;
for(var i=0;i<json[car_make].length;i++) {
select.options[select.options.length] = new Option(json[car_make][i], i);
}
}
</script>
</head>
<body>
Choose Car Make:
<select id="slct1" onchange="carModel(this)"></select>
<script> carMake(); </script>
Choose Car Model:
<select id="slct2" name="slct2"></select>
</body>
</html>
The above JS will read in the JSON object and update the Car Make when ever the dynamically populated Car Model select field is changed.
To generate the JSON object using your supplied Model you need to do the following:
In the view.py file:
from <your-app>.models import Make
from <your-app>.models import Model
import json
json_dict = {}
for car_make in Make.objects.all():
json_dict[car_make] = Model.objects.filter(make=car_make)
json_data = json.dumps(json_dict)
Then you take json_data and and add that to your response render context.
Finally alter the above template so that the JS variable json will be rendered to contain the JSON object passed from the view to the template.

You don't need javascript to do some fancy dropdown. You can use Django Forms to do it for you. All you need is to provide forms.py some information about the choices that a user can make and you will have your form rendered without you having to do anything more.
Look at my forms.py to see how I have done it.

You should convert query set to list before using json.dumps otherwise it will give you an error which is "NOT JSON SERIALIZABLE"
from <your-app>.models import Make
from <your-app>.models import Model
import json
json_dict = {}
for car_make in Make.objects.all():
json_dict[car_make] = list(Model.objects.filter(make=car_make).value())
json_data = json.dumps(json_dict)

Related

How to update my $scope after adding new data to SQL database

So I'm using angularjs/SQL technique to retrieve data from a database like so:
$http.get("retrieveData.php").then(function(response){
$scope.tasks = response.data.tasks;
})
Then I have a function that allows me to use a form to insert new data into a database:
$scope.submitTask = function(){
var description = document.getElementById("typeDescription").value;
var todayDate = document.getElementById("todayDate").value;
try{
reminder = document.getElementById("reminder").value;
}
catch(err){
reminder = "NONE";
}
var status = document.getElementsByName("selectStatus");
var statusValue;
for(i=0;i<status.length;i++){
if(status[i].checked){
statusValue = status[i].value;
}
}
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("msg").innerHTML = this.responseText;
}
};
xhttp.open("POST", "enterTask.php");
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("desc="+description+"&status="+statusValue+"&reminder="+reminder+"&todayDate="+todayDate);
}
I'm sure my first problem is that I'm using JavaScript's AJAX instead of Angular's? But I don't know how to convert it.
Even so, I don't know how to then update the $scope.tasks.
I've looked online how to POST using Angular and haven't been able to find much. Just the tutorial on how to get.
Please don't give any JQuery. I am using pure JavaScript, thank you.
Thanks to some help I've restructured my code a bit (still mixing JavaScript but I plan to research Angular forms). Here is what I have now.
$http.get("retrieveData.php").then(function(response){
$scope.tasks = response.data.tasks;
})
$scope.submitTask = function(){
var description = document.getElementById("typeDescription").value;
var todayDate = document.getElementById("todayDate").value;
try{
reminder = document.getElementById("reminder").value;
}
catch(err){
reminder = "NONE";
}
var status = document.getElementsByName("selectStatus");
var statusValue;
for(i=0;i<status.length;i++){
if(status[i].checked){
statusValue = status[i].value;
}
}
var task = {
desc:description,
status:statusValue,
reminder:reminder,
todayDate: todayDate
}
$http.post('enterTask.php', task).then(
function(response){
$scope.tasks.push(task);
}
);
}
});
For some reason though, my $scope.tasks is still not updating after I add to the element. If I add an element to an empty database I get an angular error in my console.
TypeError: Cannot read property 'push' of undefined
Sooo. Not sure why this is.
When I alert the $scope.tasks after the push, it alerts 1 less than it should actually contain after push (once there is 1 or more elements in database to not produce above error).
Here is my HTML, maybe it has something to do with it?
<ul>
<li ng-repeat="x in tasks" ng-bind="x.Description"></li>
</ul>
<form>
<input type="text" value="{{today}}" id="todayDate">
<textarea rows="15" cols="100" name="typeDescription" id="typeDescription"></textarea>
<input type="checkbox" ng-model="setReminder" name="setReminder">Set Reminder
<input type="date" name="reminder" id="reminder" ng-if="setReminder"><br>
<input type="radio" name="selectStatus" value="CR">Client Response
<input type="radio" name="selectStatus" value="IR">Internal Response
<input type="radio" name="selectStatus" value="BD">BD Control
<input type="radio" name="selectStatus" value="OC">On Calendar<br>
<input type="submit" ng-click="submitTask();">
</form>
Also my php...
<?php
/*$description = json_decode($_POST['desc']);
$reminder = json_decode($_POST['reminder']);
$todayDate = json_decode($_POST['todayDate']);
$status = json_decode($POST['status']);*/
$data = json_decode(file_get_contents("php://input"));
$description = $data->desc;
$reminder = $data->reminder;
$todayDate = $data->todayDate;
$status = $data->status;
require 'databaseConnect.php';
$query="INSERT INTO TaskTracker (DATESTAMP,STATUS,DESCRIPTION,REMINDER) VALUES ('$todayDate','$status','$description','$reminder')";
mysql_query($query) or die(mysql_error());
?>
The commented out part wasn't working so then I used the file_get_contents bit.
In angular js posting data is very easy and it can be done in just 2 to 3 lines of code.
//first lets collect your data in an Object
var data = {
desc: description,
status: statusValue,
reminder: reminder,
todayDate: todayDate
}
//then send collected data using $http service
$http.post('enterTask.php',data).then(function(response){
$scope.tasks.push(data);//After successful HTTP request you push the data to your $scope.task array
})
You have to "tackle" some points to get the submitTask function into an angular way of thinking.
Use ng-model data binding from the input elements to the $scope. There are several tutorials out there. By using this you can get rid of the whole getElementById stuff.
Use $http.post to send the data over the wire.
Update the $scope.tasks array by simply adding/removing elements. The two way data bindung of angular will do the update for you in e.g. via ng-repeat
For the last to points I sketched the JavaScript code for you.
$scope.submitTask = function(){
var description = document.getElementById("typeDescription").value;
var todayDate = document.getElementById("todayDate").value;
try{
reminder = document.getElementById("reminder").value;
}
catch(err){
reminder = "NONE";
}
var status = document.getElementsByName("selectStatus");
var statusValue;
for(i=0;i<status.length;i++){
if(status[i].checked){
statusValue = status[i].value;
}
}
var task = {
desc: description,
status: statusValue,
reminder: reminder,
todayDate: todayDate
}
$http.post('enterTask.php', task).then(
function (response) {
$scope.tasks.push(task);
}
);
}

$$hashKey match and selected value for select menu

I am trying to set selected option for the select menu but its not working because data that I am sending to ng-model has different $$hashKey from data in the select menu and $$hashKey holding for values.
<select class="form-control" ng-model="selManga" ng-options="manga.seri for manga in mangalar">
<option value="">Manga Seçin</option>
</select>
<select ng-change="selPage = 0" ng-model="selChapter" ng-options="selManga.randomword.indexOf(chapter) as chapter.klasor for chapter in selManga.randomword">
<option value="">Bölüm</option>
</select>
<select ng-model="selPage" ng-options="selManga.randomword[selChapter].yol.indexOf(page) as selManga.randomword[selChapter].yol.indexOf(page) + 1 for page in selManga.randomword[selChapter].yol">
</select>
I google it to get around with this people says track by but I have to use as. So is there a another way to get around it?
Selected value for first select menu is working but second one is not working. Here is plunker.http://plnkr.co/edit/3V8JSF2AU01ZZNPfLECd?p=info
.controller('nbgCtrl',function ($scope, MMG, $stateParams) {
var milo = $stateParams.serix;
var musti = $stateParams.klasor;
MMG.adlar.success(function(loHemen) {
var i, miloMangaInArray;
for (i=0; i<loHemen.length; i++) {
if (loHemen[i].seri===milo) {
miloMangaInArray = loHemen[i];
break;
}
};
var a;
for (a=0; a<miloMangaInArray.randomword.length; a++) {
if(miloMangaInArray.randomword[a].klasor===musti) {
break;
}
}
$scope.mangalar = loHemen; //JSON Data
$scope.selManga = $scope.mangalar[i]; // First select menu's ng-model and its working.
$scope.selChapter = $scope.mangalar[i].randomword[a]; //Second select menu's ng-model and its not working due to no matching JSON data.
});
$scope.next = function (manga, chapter, page) {
var nextPage = page + 1;
if (angular.isDefined(manga.randomword[chapter].yol[nextPage])) {
$scope.selPage = nextPage;
} else if (angular.isDefined(manga.randomword[chapter + 1])) {
$scope.selChapter = chapter + 1;
$scope.selPage = 0;
}};
})
Dude here you go, a js fiddle for the solution
http://jsfiddle.net/yw248mfu/2/
the method I used here is indexOf to get the index of the page in the array for the last select only ,,
and this is not the best solution as it will have to apply index of every time the digest loop run ,,
I can think of a number of different solutions to this ,,
1- you can extract the id of the page from the name of the image itself
2- you can map the pages array to be a list of objects with the following schema
[{"index":1,"img":"00.jpg"},{"index":2,"img":"01.jpg"},{"index":3,"img":"02.jpg"}]
you can do the second option with this piece of code
pages.map(function(d,i){return {"index":i,"img":d};});
crouch74
I think you should embrace the AngularJS way of handling models and bindings. So, instead of keeping track of all the different indexes through your view code, you can simply let ng-select assign references to parts of your model (via ng-model). By changing the HTML and controller slightly, you can simplify some of the code, and it will actually work, too.
First, make a shared $scope.model = {…} object available on the $scope. Then, change the HTML to
<select ng-model="model.selManga" ng-options="manga.seri for manga in mangalar">
<option value="">Manga Seçin</option>
</select>
<select ng-model="model.selChapter" ng-options="chapter.klasor for chapter in model.selManga.randomword" ng-change="model.selPage = model.selChapter.yol[0]">
<option value="">Bölüm</option>
</select>
<select ng-model="model.selPage" ng-options="page as model.selChapter.yol.indexOf(page) + 1 for page in model.selChapter.yol">
</select>
<img class="picture" ng-src="http://baskimerkeziankara.com/{{model.selPage}}" ng-click="next(model.selPage)">
After that, change the controller is changed accordingly:
.controller('nbgCtrl', function($scope, MMG, $stateParams) {
var model = {
selManga: undefined,
selChapter: undefined,
selPage: undefined
};
$scope.model = model;
MMG.adlar.success(function _init(loHemen) {
for (var i = 0; i < loHemen.length; i++) {
if (loHemen[i].seri === $stateParams.serix) {
model.selManga = loHemen[i];
break;
}
}
for (var a = 0; a < model.selManga.randomword.length; a++) {
if (model.selManga.randomword[a].klasor === $stateParams.klasor) {
model.selChapter = model.selManga.randomword[a];
break;
}
}
model.selPage = model.selChapter.yol[0];
$scope.mangalar = loHemen;
});
$scope.next = function _next(page) {
var pageIndex = model.selChapter.yol.indexOf(page);
if (angular.isDefined(model.selChapter.yol[pageIndex + 1])) {
model.selPage = model.selChapter.yol[pageIndex + 1];
} else {
var chapterIndex = model.selManga.randomword.indexOf(model.selChapter);
if (angular.isDefined(model.selManga.randomword[chapterIndex])) {
pageIndex = 0;
model.selChapter = model.selManga.randomword[chapterIndex + 1];
model.selPage = model.selChapter.yol[pageIndex];
}
}
console.log('manga', model.selManga.seri,
'chapter', model.selChapter.klasor,
'selPage', pageIndex + 1);
};
})
I've created a forked Plunker that shows how this works (and this solution actually works): http://plnkr.co/edit/2aqCUAFUwwXuGQHpuooj

DropDownList Change() doesn't seem to fire

So, I have been bashing my head against the desk for a day now. I know this may be a simple question, but the answer is eluding me. Help?
I have a DropDownList on a modal that is built from a partial view. I need to handle the .Change() on the DropDownList, pass the selected text from the DropDownList to a method in the controller that will then give me data to use in a ListBox. Below are the code snippets that my research led me to.
all other controls on the modal function perfectly.
Can anyone see where I am going wrong or maybe point me in the right direction?
ProcessController
// I have tried with [HttpGet], [HttpPost], and no attribute
public ActionResult RegionFilter(string regionName)
{
// Breakpoint here is never hit
var data = new List<object>();
var result = new JsonResult();
var vm = new PropertyModel();
vm.getProperties();
var propFilter = (from p in vm.Properties
where p.Region == regionName && p.Class == "Comparable"
select p).ToList();
var listItems = propFilter.ToDictionary(prop => prop.Id, prop => prop.Name);
data.Add(listItems);
result.Data = data;
return result;
}
Razor View
#section scripts{
#Scripts.Render("~/Scripts/ui_PropertyList.js")
}
...
<div id="wrapper1">
#using (Html.BeginForm())
{
...
<div id="fancyboxproperties" class="content">
#Html.Partial("PropertyList", Model)
</div>
...
<input type="submit" name="bt_Submit" value="#ViewBag.Title" class="button" />
}
</div>
Razor (Partial View "PropertyList.cshtml")
...
#{ var regions = (from r in Model.Properties
select r.Region).Distinct(); }
<div>
<label>Region Filter: </label>
<select id="ddl_Region" name="ddl_Region">
#foreach (var region in regions)
{
<option value=#region>#region</option>
}
</select>
</div>
// ListBox that needs to update after region is selected
<div>
#Html.ListBoxFor(x => x.Properties, Model.Properties.Where(p => p.Class == "Comparable")
.Select(p => new SelectListItem { Text = p.Name, Value = p.Id }),
new { Multiple = "multiple", Id = "lb_C" })
</div>
...
JavaScript (ui_PropertyList.js)
$(function () {
// other events that work perfectly
...
$("#ddl_Region").change(function () {
$.getJSON("/Process/RegionFilter/" + $("#ddl_Region > option:selected").attr("text"), updateProperties(data));
});
});
function updateProperties(data, status) {
$("#lb_C").html("");
for (var d in data) {
var addOption = new Option(data[d].Value, data[d].Name);
addOption.appendTo("#lb_C");
}
}
The callback function passed to your $.getJSON method is wrong. You need to pass a reference to the function, not to invoke it.
Try this:
$.getJSON("/Process/RegionFilter/" + $("#ddl_Region > option:selected").text(), updateProperties);
Also, in order to get the text of the selected drop-down option, you need to use the text() function:
$("#ddl_Region > option:selected").text()
See Documentation

How to mix C# with javascript for changing html?

I'm trying to change a html DOM element. With data from asp.net. All the data from CSharp is in the ViewBags. ViewBag.Kenmerken is a list of Strings and ViewBag.Definities is a list a definition object with a variable 'variabel' and the variable 'kenmerk'. I have the following code:
#{
ViewBag.Title = "KenmerkSelectie";
}
<script type="text/javascript">
function Kenmerk1() {
var myselect = document.getElementById("kenmerk1");
var selectValue = myselect.options[myselect.selectedIndex].value;
var newOptions= "";
#foreach (var def in ViewBag.Definities) {
//#def.kenmerk is C# && selectValue is JS;
if(#def.Kenmerk == selectValue){
newOpstions= newOptions+ "<option value=\"#def.Variabel\"> #def.Variabel </option>";
}
}
document.getElementById("var1").innerHTML = newOptions;
}
<div class="kenmerk">
<h3>Kenmerk 1</h3>
<select id="kenmerk1" onchange="Kenmerk1()">
#foreach (var item in ViewBag.Kenmerken)
{
<option value="#item">
#item
</option>
}
</select>
<select id="var1" multiple="multiple">
<!-- add option from js function -->
</select>
</div>
EDIT:
Description: An error occurred during the compilation of a resource
required to service this request. Please review the following specific
error details and modify your source code appropriately.
Compiler Error Message: CS0103: The name 'selectValue' does not exist
in the current context
Source Error: if(#def.Kenmerk == selectValue){
You aren't properly escaping your " (quotations). This line:
newOptions = newOptions + "<option value="#def.Variabel"> #def.Variabel </option>";
Should be something like:
newOptions = newOptions + #"<option value=""#def.Variabel""> #def.Variabel</option>";
Though, for ASP.NET MVC design principles, I'd recommend not using the ViewBag. Use a model for passing in your data instead. http://tech.trailmax.info/2013/12/asp-net-mvc-viewbag-is-bad/
EDIT:
Also, it looks like you should convert your data to JSON so that you can compare your values on the JavaScript side. Since def.Kenmerk lives in C#, it won't be able to evaluate the JavaScript variable, selectValue on an == comparison.
Try using razors <text> Pseudo-element see also here
function Kenmerk1() {
var myselect = document.getElementById("kenmerk1");
var selectValue = myselect.options[myselect.selectedIndex].value;
var newOptionsInHtmlStyle = "";
#foreach (var def in ViewBag.Definities) {
<text>
//#def.kenmerk is C# && selectValue is JS;
if(#(def.Kenmerk) == selectValue){
newOptions = newOptions + '<option value="#(def.Variabel)"> #(def.Variabel) </option>';
}
</text>
}
document.getElementById("var1").innerHTML = newOptions;
}

Change DropDownList data with Javascript

I have a page where a user can select if the transaction type is an inter accounts transfer, or a payment.
The model I pass in had two lists.
One is a list of SelectListItem
One is a list of SelectListItem
One of the lists is populated like this:
var entities = new EntityService().GetEntityListByPortfolio();
foreach (var entity in entities.Where(x=>x.EntityTypeId == (int)Constants.EntityTypes.BankAccount))
{
model.BankAccounts.Add(new SelectListItem
{
Value = entity.Id.ToString(CultureInfo.InvariantCulture),
Text = entity.Description
});
}
If the user selects 'Inter account transfer', I need to:
Populate DropdownA with the list from Accounts, and populate DropdownB with the same list of Accounts
If they select "Payment", then I need to change DrowdownB to a list of ThirdParty.
Is there a way, using javascript, to change the list sources, client side?
function changeDisplay() {
var id = $('.cmbType').val();
if (id == 1) // Payment
{
$('.lstSource'). ---- data from Model.ThirdParties
} else {
$('.lstSource'). ---- data from Model.Accounts
}
}
I'd prefer not to do a call back, as I want it to be quick.
You can load the options by jquery Code is Updated
Here is the code
You will get everything about Newton Json at http://json.codeplex.com/
C# CODE
//You need to import Newtonsoft.Json
string jsonA = JsonConvert.SerializeObject(ThirdParties);
//Pass this jsonstring to the view by viewbag to the
Viewbag.jsonStringA = jsonA;
string jsonB = JsonConvert.SerializeObject(Accounts);
//Pass this jsonstring to the view by viewbag to the
Viewbag.jsonStringB = jsonB;
You will get a jsonstring like this
[{"value":"1","text":"option 1"},{"value":"2","text":"option 2"},{"value":"3","text":"option 3"}]
HTML CODE
<button onclick="loadListA();">Load A</button>
<button onclick="loadListB();">Load B</button>
<select name="" id="items">
</select>
JavaScript Code
function option(value,text){
this.val= value;
this.text = text;
}
var listA=[];
var listB=[];
//you just have to fill the listA and listB by razor Code
//#foreach (var item in Model.ThirdParties)
//{
// <text>
// listA.push(new option('#item.Value', '#item.Text'));
// </text>
// }
//#foreach (var item in Model.Accounts)
// {
// <text>
// listA.push(new option('#item.Value', '#item.Text');
// </text>
// }
listA.push(new option(1,"a"));
listA.push(new option(2,"b"));
listA.push(new option(3,"c"));
listB.push(new option(4,"x"));
listB.push(new option(5,"y"));
listB.push(new option(6,"z"));
function loadListA(){
$("#items").empty();
listA.forEach(function(obj) {
$('#items').append( $('<option></option>').val(obj.val).html(obj.text) )
});
}
function loadListB(){
$("#items").empty();
listB.forEach(function(obj) {
$('#items').append( $('<option></option>').val(obj.val).html(obj.text) )
});
}
NEW Javascript Code fpor Json
var listA=[];
var listB=[];
var jsonStringA ='[{"val":"1","text":"option 1"},{"val":"2","text":"option 2"},{"value":"3","text":"option 3"}]';
var jsonStringB ='[{"val":"4","text":"option 4"},{"val":"5","text":"option 5"},{"value":"6","text":"option 6"}]';
//you just have to fill the listA and listB by razor Code
//var jsonStringA = '#Viewbag.jsonStringA';
//var jsonStringB = '#Viewbag.jsonStringB';
listA = JSON.parse(jsonStringA);
listB = JSON.parse(jsonStringB);
function loadListA(){
$("#items").empty();
listA.forEach(function(obj) {
$('#items').append( $('<option></option>').val(obj.val).html(obj.text) )
});
}
function loadListB(){
$("#items").empty();
listB.forEach(function(obj) {
$('#items').append( $('<option></option>').val(obj.val).html(obj.text) )
});
}
Here is the fiddle http://jsfiddle.net/pratbhoir/TF9m5/1/
See the new Jsfiddle for Json http://jsfiddle.net/pratbhoir/TF9m5/3/
ofcourse you can so that
try
var newOption = "<option value='"+"1"+'>Some Text</option>";
$(".lstSource").append(newOption);
or
$(".lstSource").append($("<option value='123'>Some Text</option>");
Or
$('.lstSource').
append($("<option></option>").
attr("value", "123").
text("Some Text"));
Link for reference
B default, I don't think the concept of "data-source" means something in html/javascript
Nevertheless, the solution you're looking for is something like knockoutjs
You'll be able to bind a viewmodel to any html element, then you will be able to change the data source of your DropDownList
see : http://knockoutjs.com/documentation/selectedOptions-binding.html

Categories