How to add CSS / HTML to a Ajax call - javascript

I'm calling my server each time a user enters / deletes a key in a search box, retrieving a large list of lists in JSON, which I loop through through in JS. In order to get the data onto my template I add HTML & CSS using Jquery. Here's an example to show what I mean...
<script type="text/javascript">
$(document).ready(function() {
$('#input-search').keyup(function(data) {
var search = $("#input-search").val();
$.get("/search/", { search:search }, function(search){
var matches = (search.search);
for (match in matches){
console.log(matches[match].full_name);
$(".searchable-container").append("<div>").addClass("items col-xs-12 col-sm-12 col-md-6 col-lg-6").append("<div>").addClass("info-block block-info clearfix").append("<div>").addClass("square-box pull-left").append("<span>").addClass("glyphicon glyphicon-user glyphicon-lg").append("<h5>")
}});
});
});
</script>
I feel like this is not the best way to style my returned data as it's requiring a lot of trial and error, and it looks ugly. For example, using Jinja templates, I can simply add {{ curly braces }} and it calls my data wherever it's needed. I'm just wondering if there is something I'm missing, or a better way to do what I'm doing, given I'm new to JQuery.

I suggest you to don't append directly the object. Just create it and then append it. Something like:
var obj1 = $("<div>");
var obj2 = $("<div>");
obj1.addClass(...);
...
$(".searchable-container").append(obj1);
$(".searchable-container").append(obj2);
But this is the way to go IMO.

Related

How to display a model data dynamically in Html?

I have a model and in a function this model is updating.
I want to display this model's data dynamically. So, new values should display without refreshing the page. How can I do it?
models.py
class MyLongProcess(models.Model):
active_uuid = models.UUIDField('Active process', null=True, blank=True)
name = models.CharField('Name', max_length=255)
current_step = models.IntegerField('Current step', default=0)
total = models.IntegerField('Total', default=0)
#property
def percentage_sending(self):
# or it can be computed by filtering elements processed in celery with complete status
return int((current_step / total) * 100)
views.py
def setup_wizard(request):
process = MyLongProcess.objects.create(active_uuid=uuid.uuid4(), name=name, total=100)
functions.myClass(..., process=process)
....
return render(request, 'setup_wizard.html', context)
functions.py
class myClass():
def __init__(self, ..., process):
self.download_all(..., process=process)
#app.task(bind=TRUE)
def download_all(self, ..., process):
....
for s in scans:
....
process.current_step += 1
process.save()
...
setup_wizard.html
<div class="progress-bar" role="progressbar"
style="width: {{ my_model_object.percentage_sending }}%;"
aria-valuenow="{{ my_model_object.percentage_sending }}"
aria-valuemin="0" aria-valuemax="100">{{ my_model_object.percentage_sending }}%
</div>
All my function works fine. When I looking the MyLongProcess from Django admin and refresh the page, values are updating. Just I want to display it in frontend without refreshing.
this is not what Django was meant for. Essentially, it renders static HTML content and that's it. what you would like to do in a time-consuming function like that is to first render some initial content (let's say with a progress of 0) and then notify the frontend asynchronously. This can be acomplished in two ways. First way is definetely easier to implement but it's slightly harder on resources - which is polling. essentially you create a special endpoint in your urls.py which, when accessed, would give you the percentage of the job you're after. then you could have a javascript code that would have setInterval( (js-code), 1000) to refresh the progress each second. Just to give you an overview how this could be implemented:
document.addEventListener("DOMContentLoaded", function(event) {
var myElement = document.getElementById('my-element');
var task_id = myElement.getAttribute('data-task_id');
setInterval(function() {
var progressReq = new XMLHttpRequest();
progressReq.addEventListener("load", function() {
myElement.setAttribute('aria-valuenow', this.responseText);
});
progressReq.open("GET", "/progress-query/?task_id=" + task_id);
progressReq.send();
}, 1000);
});
the HTTP request can really look way nicer with the help of jQuery but I wanted to just give you an idea of how this could look.
In order for this to work you'd have to amend the html template to include the id like so:
<div ... data-task_id="some-task-id" />
if you'd want to post model-related value's here keep in mind to hash them so that you don't accidentally post raw database PK or something like that.
The second approach which is slightly more complex to implement, would be to use websockets. this means that when the frontend starts, it would listen to events that are sent to it via the backend websocket implementation. This way, you could update the progress almost in real time, rather than each second. In both of the approaches, the javascript code would have to access the element you want to update - either via var element = document.getElementById( ... ) (which means you have to have an id to begin with) or with the help of jQuery. then you can update the value like so: element.setAttribute('aria-valuenow', 10). Of course with the help of the libraries like jQuery your code can look way nicer than this.
p.s. don't forget (if you go via polling approach) to break setInterval loop once the progress reaches 100 :-)

Show second checkbox if return value of first is true

I got a question and I am also accepting to getting downvotes for this because I have not really tried something yet. The problem is I don't know how to name the problem and for what I should look for around the internet.
It's like this, I got a link to an api which (in my case) contains all provinces of china in this format:
{
"result":{
"version":"1.0",
"status":100101,
"msg":"got provinces successfully"
},
"data":[
{"province":"\u9999\u6e2f"},
{"province":"\u5317\u4eac\u5e02"}
and some more. Now I want to make a dropdown select menu which contains all this provinces as dropdown values and if one dropdown is selected it should check another URL which says if the selected province is valid or not (in my case it only can be valid because the user cannot enter something himself)
?action=api&i=getCityForProvince&data=北京市
This would be the url for checking this, if it is successful it shows me the cities of the province in the same format like the code above. With this i want to make another select box which only appears if the first is true. In this select box you then select your city and that's it.
I sadly have absolutely no idea how to start with this problem and for what i should look for to solve this.
I wonder if the fact that it's chinese has anything to do with your problem? I bet, it doesn't. With jquery it's pretty easy to accomplish such tasks. It's like building blocks you need to put together.
Learn how to make ajax calls with JQuery. It's quite easy, also it should process your Json result, making it a object or array. So in the callback, you can build up your select box like described here. Another block is to bind to the change event of the select box, which is doing another Ajax call (you already know that now) using the value from the Select input. And in the result of that callback, you can also check the result json and if the result was successful, you can easily fill up another select box using already known methods now, or change its visiblity according to your results.
I think you will want to learn those things, and was not supposed to get a ready coded solution :)
To make your work easier, I recommend you to use:
a template library
an MVVM framework
The difference between using jQuery directly and an MVVM library, or template library, like handlebars or mustache, is that with jQuery you have to take care of handling the elements, and with the other solutions, you leave this work to the framework.
ANyway, I recommend using knockout over using the template libraries, because:
it includes the templates
it can provide a two-way binding
it can handle events
it can apply classes, modify visibility, enable and disable elements...
Here I add a simple example of what it can do:
// This is the ko part:
// This is the view model using Revealing Module Pattern to build it
var vm = (function(){
// The list of provinces which will be shown when available
var provinces = ko.observableArray([]);
// The province selected in the list
var selectedProvince = ko.observable();
// This is what you'd call when the provinces are loaded using AJAX
var loadProvinces = function(data) {
provinces(data);
};
// This functions will be triggered when the selected province changes...
var updateCities = function() {
console.log("Here you'd update cities");
};
// ... because of this subscription
selectedProvince.subscribe(updateCities);
// return the object with the desired properties:
return {
provinces: provinces,
selectedProvince: selectedProvince,
loadProvinces: loadProvinces,
updateCities: updateCities
};
})();
ko.applyBindings(vm);
// AJAX call simulation:
// the returned data
var data = [
{"province":"\u9999\u6e2f"},
{"province":"\u5317\u4eac\u5e02"}
];
// a time out to load the data (simulate AJAX call)
setTimeout(function() { vm.loadProvinces(data);}, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="visible: !(provinces().length)">
Please wait while loading provinces
</div>
<div data-bind="visible: provinces().length">
<select data-bind="options: provinces,
optionsText: 'province',
optionsValue: 'province',
value: selectedProvince">
</select>
<p>Selected province: <span data-bind="text: selectedProvince"></span></p>
</div>
As you can see, it handles not only creating the DOM elements, bu also handling events, two way-bindig, detecting changes in values...
You could originally write the HTML for your second checkbox and give it a display: none; property. Then on the JS:
if (firstcheckboxValue === true) {
document.getElementById('secondCheckboxId').style='display: block';
}
You could use display: inline-block; or display: inline; etc, whatever suits your layout better.
Things would drastically get easier if you used jQuery. Since there's no code to start working with, I'll just list out steps I'd go through.
1) Write DOM elements for dropdowns, say #dd_provinces #dd_cities. #dd_cities would be hidden.
2) From $().ready(function(){...}) I'd make the web API call.
3) From result callback of the API call in #2, make the second API call(one to fetch cities of the province).
4) Result callback of the second API callback will populate the DOM element #dd_cities
5) Unhide #dd_cities
Sample code:
HTML
<select id="dd_provinces">
</select>
<select id="dd_cities" style="visibility: hidden">
</select>
JS
$(document).ready(function() {
$.ajax({
url: "/echo/json/",
data: "",
success: function(evt) {
var mData = ["City 1", "City 2", "City 3", "City 4"];
for(var i = 0; i < mData.length; i++){
var optionElem = "<option>" + mData[i] + "</option>";
$("#dd_provinces").append(optionElem);
}
$.ajax({
url: "/echo/json",
data: "",
success: function(evt) {
$("#dd_cities").css("visibility", "visible").animate('5000');
}
});
},
error: function(evt) {
console.log(evt);
}
});
});

I'm getting a "newItem() was not passed an identity for the new item" error while trying to add a new item to a JSON store

I've seen other posts in this site regarding the same issue and I've tried the solutions given. I've also visited the links that may offer a solution but I'm still stuck with the same error.
I'm using DOJO and something as simple as this won't even work
myStore.newItem({id: 'test', otherfield: 'otherinfohere'});
myStore.save();
Supposedly the "newItem() was not passed an identity for the new item" error appears when you haven't provided an identifier for the new item, which i have.
The whole purpose of this (Just in case anyone can provide a good idea or has done something similar before) is that i want to create a data grid that shows info from a particular store. The problem is, that in that store all the items may not have the same structure. For instance:
I may have a store that looks like this
{identifier: 'id',
label: 'name',
items: [
{ id:'1', name:'Ecuador', capital:'Quito' },
{ id:'2', name:'Egypt', capital:'Cairo' },
{ id:'3', name:'El Salvador', capital:'San Salvador' , additionalField: 'otherinfohere'},
{ abbr:'gq', name:'Equatorial Guinea', capital:'Malabo', additionalField: 'otherinfohere'},
]}
This is possible because I'm the one constructing the store in a Spring Controller (I'm also using the Spring Framework) from information I have locally stored in a Berkeley DB. So what i need is a data grid with a dynamic layout because I don't want blank spaces to show in the view in the rows with lesser amount of fields, and i need to show all the info in the store at the same time, but i don't know how to do this.
I thought of doing it by creating a simple layout of only 1 field. In it I would load data from a store i create dynamically at runtime. The data in the store would be composed of HTML combined with the values coming from the original store so I could obtain something like this, which is inside an attribute of a JavaScript Object and let the browser parse it for me:
<div><span>id: originalID </span>....</div>
This of course is a simple example, the html layout i'm looking for is far more complicated, but i think that passing it as a string to an object might do the trick.
The problem is that i don't even know if that idea will work because i get that error whenever i try to add values to my secondary store.
rdb.modules.monitor.historicStore.fetch({onComplete: function(items, request){
for (var i = 0; i < items.length; i++){
var item = items[i];
var obj = new Object();
obj.id = rdb.modules.monitor.historicStore.getValue(item, "id");;
var html = "<div><span>";
html += rdb.modules.monitor.historicStore.getValue(item, "sql");
html += "</span></div>";
obj.html = html;
myStore.store.newItem(obj);
}
}});
In this context "historicStore" refers to the JSON store that has the values that i need to convert and add to "myStore" after i added some HTML.
I hope you got the main idea of what I'm trying to do. If anyone can help me we either of these problems i would really appreciate it. Thanks in advance
For the issue regarding store:-
"id" is mandatory for a store, if it is going to be used for a grid(datagrid, EnhancedGrid, etc. whatever). The items are handled only on basis of "id" attribute by the grid data structures.
Usually, id can be a loop variable/ auto incrementation, to avoid any cases like you have said. Before adding the store to the grid, ensure that all items have the id attribute. You can write a function which will loop through each item and check for this, else add an auto-incrementing value for the id attribute of that item.

sp.js get all lists by content type

I have combed through the sp namespace docs and not found much to go on.
I found this snippet from http://www.c-sharpcorner.com/Blogs/12134/how-to-get-the-list-content-types-using-csom-in-sharepoint-2.aspx
//// String Variable to store the siteURL
string siteURL = "http://c4968397007/";
//// Get the context for the SharePoint Site to access the data
ClientContext clientContext = new ClientContext(siteURL);
//// Get the content type collection for the list "Custom"
ContentTypeCollection contentTypeColl = clientContext.Web.Lists.GetByTitle("Custom").ContentTypes;
clientContext.Load(contentTypeColl);
clientContext.ExecuteQuery();
//// Display the Content Type name
foreach (ContentType ct in contentTypeColl)
{
Console.WriteLine(ct.Name);
}
Console.ReadLine();
which will get a a certain lists content type.
My thought is get all lists, then get all their content types, then use their id/title to query the lists for data.
It seems like a ton of work to do in a display template.
Am I on the right path or is there something I'm missing? Any sp wiz out there care to weight in on the new search/js architecture?
You may want to use a JavaScript library like SharepointPlus or the popular SPServices.
I think the syntax of SharepointPlus is simplier and the code would be something like:
$SP().lists(function(list) {
for (var i=0; i<list.length; i++) {
// list[i]['Name'] contains the name of the list
$SP().list(list[i]['Name']).get(/* something */)
}
});
You said something about the content types. So you may also want to look at the info() function and check the field with the name "ContentTypeId".
FYI I created this SharepointPlus library.

Windows 8/ Metro UI data-binding javascript

I am creating an application using javascript/HTML for windows 8 which basically displays text which is pulled from an html file.
I am using the data.js file to organise groups and items. One of the properties is the 'url' which stores the url of the html page which contains the main content for the application.
I came up with this code to retrieve the html code from the html page which contains the content to be displayed:
WinJS.UI.Fragments.renderCopy(url)
.done(function (fragment) {
return fragment;
});
How do I run this code for each item in the array in data.js and bind the data so that the content is from the HTML page, and the headings/titles are from the data.js file?
I apologise if I'm causing any confusion. I would appreciate any help.
Thanks.
Assuming you want to stick with the layout of data.js and not create your own data classes, I would use a custom renderer for the listview.
Something like this...
var customRender = WinJS.Utilities.markSupportedForProcessing(function (itemPromise) {
var currentItem = {};
return itemPromise.then(function (item) {
currentItem = item;
var myDiv = document.createElement("div");
return WinJS.UI.Fragments.renderCopy("/html/1_BasicFragmentLoad_Fragment.html", myDiv)
})
.then(function (fragment) {
var itemTemplate = WinJS.Utilities.query('.itemtemplate')[0];
currentItem.data.title = fragment.innerHTML;
return itemTemplate.winControl.render(currentItem.data);
});
}
);
In this example, I am binding the content of a html fragment to the title of a given item from data.js. You will need to update the itemtemplate and bind the title element to innerHTML instead of textContent.
<h4 class="item-title" data-win-bind="innerHTML: title"></h4>
You will also need to assign the custom renderer to the listview. You can do this in the HTML markup or just change the template js in groupItems.js to this...
listView.itemTemplate = customRender;
If you were to create your own data classes, you may want to put the promise chain from the customer renderer into the class constructor, eliminating the need for a customer renderer.

Categories

Resources