I have a simple form with the the following inputs:
type (radio) and parent (select)
Depending on the type selected, there should be different options for the select. So whenever type is selected, it should make the json request to get a list of parents based on the type.
So far what I have:
json request (in template page)
$.getJSON("{% url 'locations_by_type' %}", {type: type}, function(locations) {
var locations_select = $("select[name='parent']");
$.each(locations, function (index, value) {
locations_select.append($("<option/>", {
value: key,
text: value
}));
});
});
forms.py
class LocationForm(forms.Form):
LOCATION_TYPE_COICES = (
("country", "country"),
("state", "state"),
("county", "county"),
("town", "town"),
)
name = forms.CharField(max_length=45)
type = forms.ChoiceField(
choices=LOCATION_TYPE_COICES,
widget=RadioSelect(),
required=True,
)
parent = forms.ChoiceField(
label = 'Parent Location',
widget = Select(),
required = False,
help_text = "If you do not choose a parent location, this location will not appear on the locations page"
)
views.py
def locations_by_type(request):
locations = Location.objects.get(type=request.GET["type"])
return json.dumps(locations)
urls.py individual pattern
url(r'^/locations_by_type', views.locations_by_type, name='locations_by_type'),
And when I load the form, the form itself loads fine, however I get an error from the request in the javascript console:
GET http://locations_by_type/?type=state net::ERR_NAME_NOT_RESOLVED
Any ideas as to what I am doing wrong here?
UPDATE 1
I had a "/" in front of locations_by_type in the url regex previously. After fixing this, the javascript console reported a 500 Internal Server Error
The Django error that is logged in the manage.py runserver window is:
TypeError: <Location: SC> is not JSON serializable
UPDATE 2
I have managed to get rid of the 500 internal server error, however the data doesn't return as expected. I believe it has something to do with how I iterate over the returned locations list in the location.html script, but I'm not positive.
My forms.py remains the same as it was when this question was asked.
views.py
def locations_by_type(request):
locations = Location.objects.filter(type=request.GET["type"]).values('id', 'name')
data = json.dumps(list(locations), cls=DjangoJSONEncoder)
return HttpResponse(data, content_type='application/json')
location.html script
<script>
//Update Location Select box given a type
function updateLocations(type) {
$.getJSON("{% url 'locations_by_type' %}", {type: type}, function(locations) {
var locations_select = $("select[name='parent']");
$.each(locations, function (index, value) {
locations_select.append($("<option/>", {
value: index,
text: value
}));
});
});
}
//If there is a type selected at document load, make sure parent select
// has the appropriate values, otherwise hide it
$(document).ready(function() {
if ($("input[name='type']:checked").size() == 0) {
$("select[name='parent']").parent().parent().hide();
} else {
var type = $("input[name='type']:checked").val();
updateLocations(type);
}
});
//Whenever type is changed, make sure the parent select is shown and has
// the appropriate values
$("input[name='type']").change(function() {
$("select[name='parent']").parent().parent().show();
var type = $("input[name='type']:checked").val();
updateLocations(type);
})
</script>
Finally, what I get returned is:
<select id="id_parent" name="parent">
<option value="0">[object Object]</option>
<option value="1">[object Object]</option>
....
</select>
However, I would like:
<select id="id_parent" name="parent">
<option value="[location.id]">[location.name]</option>
<option value="[location.id]">[location.name]</option>
....
</select>
Related
Code fragment look like this:
const data = {
title: title,
area: area,
category: category,
body: body,
fileUrl: image.path,
fileType: image.mimetype,
};
await queryRunner.manager
.createQueryBuilder()
.update(PostEntity)
.set(data)
.where('id = :id', { id })
.execute();
And when image.path is undefined or any value from data object, I got error
UpdateValuesMissingError: Cannot perform update query because update values are not defined. Call "qb.set(...)" method to specify updated values.
It works fine without transactions, undefined value in object means it doesn't assign new value to DB.
I am stuck on this problem from quiet sometime. I have created a table with 3 columns out of which the for two columns I can use prop property to display the contents of each row for those two columns. Now, for the third column, I want to display contents from another array, how do I display this information in the third column.
Please find the example of the code below:
This is the HTML Code
<el-table :data = "data_table">
<el-table-column
prop = "Id"
label= "Unique ID">
</el-table-column>
<el-table-column
prop = "color"
label = "Color">
</el-table-column>
<el-table-column
prop = ""
label = "Count">
<template slot-scope="scope">
<el-button type="text" #click="dialogVisible = true; get_total_count_users(scope.row)">{{users.length}}</el-button>
<!--Skipping the code for dialog box..I have tested that part pretty well, so I know it works. -->
</template>
</el-table-column>
</el-table>
This is the javascript part of the code:
<script>
export default {
data(){
return{
data_table:[], // I fill the data_table array using some AJAX/Axios calls which has props Id and Color.
users: [], // I fill the users array using some AJAX/Axios calls which has multiple user information.
};
},
methods:{
get_total_count_users(row){
// axios call, etc. This part works successfully, I checked the values.
}
}
</script>
A little explanation for the above code:
I make an AJAX/Axios call to an API which return me a list/array of value in data-table array. It had two props in it, that is Id and Color. I make another axios/AJX call to an api which returns me the list of the users based on the Id present on that row of the table. Each row will have a unique Id. Using that Id, I make an axios call to an api .. example, www.example/{{Id}}.com .This returns me a list of users linked to that id. Now, my next task is to display the total users (by taking the length of the users array) and displaying it as a button. But, as I am not using prop to display the values (length of users array for each row), the value in the button is displayed the same through all the rows. It keeps changing for the entire column if I click a button on any of the rows.
get_total_count_users(scope.row) function is used to make an axios/AJAX call to www.example/{{Id}}.com and stores multiple user information tied with that Id in users array.
Please refer to the image below:
Initially, all values are 0, as the Id in the first row has 0 users attached to it.
When I click on the 3rd rows button (which initially has 0 in it), all the values in that column change to 2, as the Id in the 3rd row has two users tied to it.
Hence, the issue here is that, I simply want to display total number of users (count) each row based on that id without using the prop property.
Hope the above explanation and example is helpful to understand the problem.
Any help would be appreciated.
The answer will solve the problem but is not a specific solution that is defined to get data from multiple arrays into your data table.
You can chain your axios responses and then use a foreach to add the variables to your object inside array.
So I am assuming that you are calling a method on mount like this:
data: () => ({ tableData: [] }),
mounted() {
this.getData();
}
now within your getData() function make different axios calls and put your response into the table, with something like this.
methods: {
getData() {
var myTableData = [];
axios({ method: 'GET', url: 'http://first-url', headers: [...] }).then(res => {
//we have got the table data here
myTableData = res.data;
//looping through data and making axios calls based on data.
myTableData.foreach((row, index) => {
var newUrl = 'https://getdatafrom.com/'+ row.id+'/'; //using the data from previous call.
axios({ method: 'GET', url: newUrl, headers: [...]}).then(res2 => {
var counts = res.data;
// adding variable myCount to the table data array.
row.myCount = counts[index];
}).catch(err => { console.error(err)})
})
// setting data object
this.tableData = myTableData;
}).catch(err => { console.error(err) })
}
}
let me know if you have any issue.
My node.js MySQL query returns a single row wrapped in [RowPacketData] which I can normally access the ID field using results[0].ID.
However, when I store the result in React state (using hooks) it does not work. I can access the result object, but not fields within it.
function MyReactComponent() {
const [dbEntry, setDbEntry] = useState();
useEffect(() => {
const fetchData = async () => {
const result = await queryFunc(`SELECT * FROM table LIMIT 1`);
console.log(result[0]); // <-- Works (shows [RowDataPacket] object)
console.log(result[0].ID); // <-- Works (shows ID)
setDbEntry(result);
};
fetchData();
}, []);
console.log(dbEntry[0]); // <-- Works (shows [RowDataPacket] object)
console.log(dbEntry[0].ID); // <-- TypeError: Cannot read property '0' of undefined
return (
<p>
{dbEntry[0].ID} // <-- How do I render here?
</p>
)
}
What's going on here? I have a feeling React is coercing the result object somehow, but I can't figure it out...
When you need to display data that comes from an async font(API calls for example), it's possible (actually almost certain) that it won't be available by the time the first render occurs, to solve that there is actually a few things you could do:
Placeholder state
You could have a model of what the data will look like described as your initial state, so properties won't be undefined anymore:
const [state, setState] = useState({
data:[
{name: ''}
]
})
Assuming that your data will have this format accessing state.data[0].name won't throw an error. This could be useful in some cases but I personally don't like the approach.
Conditional Render
At each render you should check for a condition and only if satisfied render the piece of code:
return(
<>
<div>Title</div>
{Boolean(state.data.length) && <div>{state.data[0].name}</div>}
</>
)
Suspense
That one is brand new, if you have a component tha't need to perform side effects before render it's content, you should have a fallback content to be displayed while the async action is being perform.
<Suspense fallback={<span>Loading</span>}>
<MYAsyncComponent />
</Suspense>
I have a rails app running alongside with a rails API, there is a constant value for DAYS_LIMIT in config/initializers/constants.rb
DAYS_LIMIT = 40
DEFAULT_PRICE = 1.29
but now in the app i added an input field so that the user decide his DAYS_LIMIT.
So i want to fetch that value from the database from inside the API models.
I have placed breakpoints and can see that inside the API controller, the data is transfered from the app but not to the models.
edited as a question requested , it's a React-on-Rails app , here is the code where the new input field is save to the database (i have removed the other fields so the question look shorter)
export const saveChannel = (files) => {
return async (dispatch, getState) => {
const { channel } = getState();
const {rss_podcast_days} = channel;
const { image } = files;
const save = id ? updateChannel : createChannel;
const sub_required = subscription_required !== undefined ? subscription_required : false;
const formData = new FormData();
formData.append('channel[rss_podcast_days]', rss_podcast_days || '');
if (Object.keys(image).length) {
formData.append('channel[image]', image);
}
const channelId = await dispatch(save(formData, id));
dispatch(fetchChannel(id));
return id;
};
};
from the app controller
podcast_list = RestClient.get("#{ENV['URL_API']}/api/#{#channel.id.as_json}/podcast/list")
#podcasts = JSON.parse(podcast_list.body)
#podcasts = #podcasts.sort.reverse.to_h
this is from the API controller witch the data is transfered from the app
def index
podcasts = #channel.podcasts.published.list(params[:page], params[:items_per_page], params[:ordered_in])
render json: Podcasts::Normalizer.normalize(podcasts, #channel.station.default_podcast_price)
end
and here from the API model that i want to fetch data instead of the constants.
scope :by_days_limit, -> {with_tags.more_recent_than(Date.today - DAYS_LIMIT.days).ordered}
it should take today date minus the value (DAYS_LIMIT) from user input, but for now i get undefined local variable or method if i try to fetch directly
Bro if your class has constant like DAYS_LIMIT you can access it using that class itself for example,
class Demo
DAYS_LIMIT = 5
end
you can access that constant by Demo.DAYS_LIMIT in controller or else wherever you need it.
good luck!
ok , so i finally got it, i don't know if i should delete this thread or just tell how i did it. If it's inapropriate just tell me and i will delete this entire thread.
So here is how i did it, in the API controller i had to add my fetch so that the arguments (list) knows what i am talking about. #channel.days_limit
def index
podcasts = #channel.podcasts.published.list(params[:page], params[:items_per_page], params[:ordered_in], #channel.days_limit)
render json: Podcasts::Normalizer.normalize(podcasts, #channel.station.default_podcast_price)
end
then in the def list of the models, i added days_limit has argument
def list(page = nil, nb_items_per_page = 40, ordered_in = 'desc', days_limit)
ordered_in = ordered_in.in?(['asc', 'desc']) ? ordered_in : 'desc'
page.blank? ? by_days_limit(days_limit) : by_page(page, nb_items_per_page, ordered_in)
end
and finally in the scope of the models, i pass in the new argument
scope :by_days_limit, -> (days_limit) {with_tags.more_recent_than(Date.today - days_limit.days).ordered}
Now the user input from the app is passing to the models via the controller.
I am trying to create a combo box with a list of countries in SAP UI5.
I have created a combo box and have created dynamic list of some countries, but to create more than 100 countries, the only easy way is to create a JSON file of countries and then populate in Controller.js.
I tried to create a JSON file but I am unsure whether I have to store it under model folder or root.
What changes do I have to make in my XML view and controller, and where should I attach countries.json file?
You are looking at something called as "Aggregation Binding" Aggregation Binding in XML views
Here is an example to refer to which explains
How to create a model using data from json file
How to Bind model data to the XML view control(you have to bind comboBox instead of table)
How to bind json data model to an XML view
Let me know if this helps.
Maybe you don't need to create the countries.json file at all :)
As UI5 leverages Common Locale Data Repository (CLDR) internally and provides the data via sap.ui.core.LocaleDataAPI, which includes language names, country names, currency names, singular/plural modifications, and more..
A list of supported regions for the locale data are stored in a JSON format here. In one of those files, if you look at the property "territories", you'll see that the country names are listed among them. You can filter every irrelevant territory out that is not considered a country, and then bind the rest in the items aggregation of the combo box.
Demo
sap.ui.getCore().attachInit(() => sap.ui.require([
"sap/ui/core/Locale",
"sap/ui/core/LocaleData",
"sap/ui/model/json/JSONModel",
"sap/ui/core/mvc/XMLView",
], function(Locale, LocaleData, JSONModel, XMLView) {
"use strict";
XMLView.create({
definition: `<mvc:View xmlns:mvc="sap.ui.core" xmlns="sap.m"
height="100%"
displayBlock="true">
<ComboBox class="sapUiTinyMargin"
width="15rem"
placeholder="Select a country.."
filterSecondaryValues="true"
showSecondaryValues="true"
items="{
path: '/',
templateShareable: false,
key: 'code',
sorter: { path: 'name' }
}">
<core:ListItem xmlns:core="sap.ui.core"
key="{code}"
text="{name}"
additionalText="{code}" />
</ComboBox>
</mvc:View>`,
models: createCountryModel(getCountries()),
}).then(view => view.placeAt("content"));
function createCountryModel(countries, sizeLimit = 300) {
const model = new JSONModel(countries);
model.setSizeLimit(sizeLimit);
model.setDefaultBindingMode("OneWay");
return model;
}
function getCountries() {
const territories = getTerritories();
return extractCountriesFrom(territories, byCustomCheck());
}
function getTerritories(localeId) {
const currentConfig = sap.ui.getCore().getConfiguration();
const locale = localeId ? new Locale(localeId) : currentConfig.getLocale();
const localeData = new LocaleData(locale);
return localeData.getTerritories(); // includes country names
}
function extractCountriesFrom(territories, customCheck = () => true) {
const isValidCountry = createCountryCheck(customCheck);
const toObject = code => Object.freeze({
code: code,
name: territories[code],
});
const countryObjects = Object.keys(territories)
.filter(isValidCountry)
.map(toObject);
return Object.freeze(countryObjects);
}
function createCountryCheck(customCheck, obviouslyNotCountries = [
"EU", // "European Union"
"EZ", // "Eurozone"
"UN", // "United Nations"
"ZZ", // "Unknown Region"
]) {
return territoryCode => territoryCode.length == 2
&& !obviouslyNotCountries.includes(territoryCode)
&& customCheck(territoryCode);
}
function byCustomCheck() { // returns a function that returns boolean
// E.g.: list of sanctioned countries you want to exclude
const list = [
"AF",
"KP",
"IR",
// ...
];
return countryCode => !list.includes(countryCode);
}
}));
<script id="sap-ui-bootstrap" src="https://ui5.sap.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.ui.core, sap.m"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-async="true"
data-sap-ui-compatversion="edge"
data-sap-ui-xx-waitfortheme="init"
></script>
<body id="content" class="sapUiBody sapUiSizeCompact"></body>
As you can see in the example, the ComboBox is successfully populated with the countries. When a new LocaleData instance is created, a request is sent immediately (currently via sync XHR) to get the data which are translated in the language that UI5 detects from the client settings. If no language could be detected, the en.json file will be retrieved.src
The above approach has the following advantages:
No need to create and maintain a separate "country" list. ✔️
Multilingual support ✔️
Reusability ✔️ - When UI5 tries to fetch the same locale data file, which is the case when e.g. a Calendar is used, the browser can serve the file quickly from the cache since the same file was already fetched before.
Note
When creating a JSONModel to store more than 100 country names, keep in mind to increase the size limit as well. The current default limit is 100.