How to create dynamic javascript objects from Json? - javascript

I don't know how to create dynamics javascript objects:
I've tried this code but it doesnt work...
Any Idea ?
Somebody tells me " Create the element outside the Ajax Scope " ...
I want to access one of my javascript objects, that are supposed to be sorted into an array called element.
For example, element[1] is one object, element[2] is another object.
The whole array of objects is built from a json ajax call with jquery.
It works very well for the reading ... but its not possible to modify my objects in another part of my program.
It's not asynchronous problem, it seems to be an object name problem like the [] .
Thanks a lot for your precious answers ! I'll try to modify the code... It's so exciting to create objects ! My goal is that the user is able to modify several differents forms at the same time, each form is an object but i don't wanna use Php hi hi... I generate the forms using my print function.
This is the snipe of my code :
/* PHASE 1*/
$.ajax({
type: "POST",
url: "lectureBdd.php",
dataType: "json",
success: function (data) {
//CREATE JAVASCRIPTS OBJECTS
var element = 0;
var element = [];
for (var i = 0; i < data.length; i++) {
element[i] = new Element([i], data[i].nom, data[i].
type, data[i].photo, data[i].taille, data[i].prix);
// OBJECTS TO SCREEN WORKS WELL INTO THE FUNCTION BUT NOT OUTSIDE
element[i].print();
alert(element[i].prix);
}
}
});
element[2].print(); /* Impossible to modify my object*/
/* CONSTRUCTOR CLASSE "ELEMENT" */
function Element(id,txtNom,txtType,txtPhoto,txtTaille,txtPrix){
this.id=id;
this.nom=txtNom;
this.type=txtType;
this.photo=txtPhoto;
this.taille=txtTaille;
this.prix=txtPrix;
this.print=affForm;
this.modif=modifForm;
}
/* THE REST OF THE CODE FOR INFORMATION IT CREATES AUTOMATICALLY A FORM WITH THE OBJECTS VARIABLES */
function affForm(){
var nom= this.nom;
var id=this.id;
var divid = 'div'+id;
var savebutton= 'savebutton'+id;
/* DYNAMIC FORM CREATION: */
/* http://stackoverflow.com/questions/17431760/create-a-form-dynamically-with-jquery- and-submit */
$("#share").append('<form action="sharer.php" method="POST">');
$("#share").append('<div id='+divid+' style="height:100px;background-color:white" > <img src="images/'+this.photo+'" height=100px width=150px />');
$("#share").append('<input type="text" placeholder="'+nom+'" name="routename" id="rname"/>');
$("#share").append('<input type="text" placeholder="'+this.taille+'" name="routename" id="rname"/>');
$("#share").append('<input type="text" placeholder="'+this.prix+' Euros" id="prix" name="prix" class="address"/>');
$("#share").append('<input type="text" placeholder="'+id+'" id="rdescription" name="routedescription" class="address"/>');
$("#share").append('<input type="text" placeholder="tags" id="tags" name="routetags"/>');
$("#share").append('<br><input type="submit" id="'+savebutton+'" value="Save" />');
$("#share").append('</div>');
$("#share").append(divid);
$( "#"+savebutton+"").click(function() {
modifForm(id);
alert( "Handler for .click() called. savebutton"+id+"" );
});

You're creating an Array of Elements inside of your Ajax function's success callback. That isn't exposed to the outer scope, so you can't index that array later on (it isn't defined). Declare it in the scope you're calling it from.
Also, Ajax is asynchronous: your array won't have any elements until its success function runs, which can take any amount of time. You'll need to operate asynchronously, too. Have a look at jQuery's implementation of promises, which should point you in the right direction.
var element = [];
$.ajax({
type: "POST",
url: "lectureBdd.php",
dataType: "json",
success: function (data) {
for (var i=0; i < data.length; i++){
element[i] = new Element([i],data[i].nom,data[i].type,data[i].photo,data[i].taille,data[i].prix);
// OBJECTS TO SCREEN WORKS WELL INTO THE FUNCTION BUT NOT OUTSIDE
element[i].print();
alert(element[i].prix);
}}})
.done(function(){
element[2].print(); // Ajax is async; you'll need to operate async, too. Using a promise here.
});

Related

Two buttons, two instances of control class

ECMAScript 6
So far there are two buttons on the page: edit and delete. There will be more (add comment etc.). So, I would like to develop some general approach and not just operate on each button individually.
Each button is of class "custom-control" and should send an AJAX request.
Into the button tag I have included the information necessary for the request (url etc.):
<button id="main-object-delete" data-url="{{ object.get_delete_url }}" data-redirect="{{ object.get_delete_success_url }}" type="button" class="custom-main custom-control custom-delete btn btn-default " aria-label="Left Align">
The code:
$( document ).ready(function() {
class GeneralManager {
// Creates managers for each type of controls.
constructor() {
this.handle_buttons();
} // constructor
handle_buttons(){
let $button_list = $('.custom-control')
$button_list.each(function(index, button){
let button_manager = new ControlManager(button);
});
}
} // GeneralManager
function show_get_form(data, button, url, redirect){
let nest = button.closest(".custom-nest")
nest.innerHTML = data;
let act_cancel_manager = new SubmitCancelManager(url, redirect);
}
class ControlManager {
// Operates on main object only.
ajax_get(){
$.ajax({method: "GET",
url: self.url,
success: function(data){ show_get_form(data,
self.button,
self.url,
self.redirect); },
error: generalFail
});
} // ajax_get
constructor(button){
self = this; // Protection against binding "this" to something else.
this.button = button;
this.url = this.button.getAttribute("data-url")
this.redirect = this.button.getAttribute("data-redirect")
this.button.onclick = this.ajax_get;
} // constructor
}
let general_manager = new GeneralManager();
}); // $( document ).ready(function()
The idea was that for each button a new ControlManager object is created.
The problem is that both buttons trigger the request to the url for deletion. Delete button was the last of the two. If I change the order of the buttons, both buttons will send the request to the edit url.
Could you help me understand why my idea of assigning a separate instance of the ControlManager class to different buttons doesn't work. And how to cope with this problem most elegantly?
constructor(button){
self = this;
This creates a (=one) variable named self. So the second instance overwrites the value set by the first one.
ajax_get(){
$.ajax({method: "GET",
url: self.url,
Here you refer to the global variable self.
Forget self and use arrow functions where necessary:
ajax_get(){
$.ajax({method: "GET",
url: this.url,
success: data => show_get_form(data,
this.button,
this.url,
this.redirect),

Sending a Javascript array to controller ASP.NET MVC

I'm trying to store user input in a javascript array and send it to controller via ajax call. But all I get in controller's parameter is null.
Here's the code:
<table class="table-condensed table-bordered table-striped table-responsive">
#foreach (var project in projects)
{
<tr>
#foreach (var parameter in parameters)
{
<td>
<input type="text" class="form-control remar" id=#i />
</td>
i++;
}
</tr>
}
<tr>
<td colspan=#(parameters.Count() + 1)>
<button class="btn btn-primary pull-right" onclick="insert()">Submit Remarks</button>
</td>
</tr>
</table>
<script>
function insert() {
var remarks = [];
jQuery(".remark").each(function () {
remarks.push(jQuery(this).val());
});
$.ajax({
type: "POST",
url: "#Url.Action("AddRemarksToEvaluationSheet", "Teacher")",
data: JSON.stringify({ function_param: remarks }),
contentType: "application/json; charset=utf-8;"
});
}
</script>
Controller:
public ActionResult AddRemarksToEvaluationSheet(string[] function_param)
{
return View();
}
Any help?
P.S. the above code is edited. It worked!
You've got lots going on here...
First, don't give your input boxes ids of numbers - in this scenario, it doesn't look like you even use the value...But if you need it, put the value into a data element:
<input type="text" class="form-control remark" data-remark-id="#i" />
When retrieving the values, you need to get the value, not the textbox itself:
var remarks = [];
jQuery(".remark").each(function() {
remarks.push(jQuery(this).val());
});
When doing anything weird with parameters, like arrays or complex objects, if you use JSON instead of the default of URL-encoded, it will make things nicer.
You should also avoid absolute paths, and use Url.Action instead, so that it'll work regardless of where your app lives relative to the domain.
$.ajax({
type: "POST",
url: "#Url.Action("AddRemarksToEvaluationSheet", "Teacher")",
data: JSON.stringify({ function_param: remarks }),
contentType: "application/json; charset=utf-8;"
});
And you can accept an array of strings, rather than of objects:
[HttpPost]
public ActionResult AddRemarksToEvaluationSheet(string[] function_param)
{
}
I have a feeling that you aren't getting the remarks in the array in the first place.
If you aren't already, use a browser that allows you to debug the js. If you use Chrome, right-click -> inpsect element (or F12). Go to the 'Sources' tab, go to your js file and put a break point to see what the remarks array looks like.
Regarding the code:
You do not seem to need id attributes on the inputs. Let alone numerical ids.
To populate the remarks array, get all dom elements having the class you placed on all inputs. For each one, push the value in the array.
var remarks = [];
$(".form-control").each(function() {
remarks.push($(this).val());
});
You can add extra code to only add the ones with value.
var remarks = [];
$(".form-control").each(function() {
if($(this).val().length){
remarks.push($(this).val());
}
});
The ajax call:
$.ajax({
type: "POST",
url: addRemarksUrl,
data: JSON.stringify({ function_param: remarks }),
contentType: "application/json; charset=utf-8;"
});
Where addRemarksUrl can be a global variable declared in the html.
There are other ways of getting the url. Have a look here:
How to send razor created Url to js file
This user offers 3 possible solutions:
global js variable
custom "data-" attribute
hidden input

Retrieving xml namespace child element value using jquery

Folks.
I am new to jquery and I checked out alot of the postings here when it comes to parsing namespace formatting .xml using jquery. After going over my code and looking at the examples I am struggling grabbing a value from a nested child element. Below is my xml snippet:
<offers:offer-bundle>
<cash:offer lang="EN" offer-type="Cash">
<cash:cash>
<cash:cannot-be-combined-with></cash:cannot-be-combined-with>
<cash:cash-amount>1000</cash:cash-amount>
<cash:requires-tfs-financing>false</cash:requires-tfs-financing>
<cash:stackable-with-apr>false</cash:stackable-with-apr>
<cash:stackable-with-lease>false</cash:stackable-with-lease>
<cash:sub-type-labels>Cash Back</cash:sub-type-labels>
</cash:cash>
<cash:tfs-calculator>false</cash:tfs-calculator>
<cash:offer-label>Cash Back</cash:offer-label>
<cash:offer-label-num>7</cash:offer-label-num>
<cash:series-list></cash:series-list>
<cash:offer-id>cash_1433205220095</cash:offer-id>
<cash:start-date>2015-06-02</cash:start-date>
<cash:end-date>2015-07-06</cash:end-date>
<cash:title>2015 Cash Back Offer</cash:title>
<cash:use-for-email>false</cash:use-for-email>
<cash:description>I can get this value</cash:description>
<cash:offer-image/>
<cash:offer-image-alt/>
<cash:offer-image-disclaimer/>
<cash:offer-card>...</cash:offer-card>
<cash:bullets>...</cash:bullets>
<cash:disclaimers>
<cash:disclaimer>
**I NEED TO GET THIS CHILD ELEMENT VALUE.**
</cash:disclaimer>
</cash:disclaimers>
</offers:offer-bundle>
I am able to get the value of <cash:offer-card>, <cash:offer-id> etc. since it does not have any nested children. I am struggling with getting the child node of <cash:disclaimers>.
Here is what I've written so far:
$.ajax({
type : "GET",
url : webServiceURL,
dataType : "xml",
success : function (xml) {
$(xml).find('offers\\:offer-bundle, offer-bundle').each(function(index, value) {
var $incentive;
var $offer;
var $offerDescription;
var $offerDisclaimer;
//Do Cash: Condition code is executing, incentive is hard coded to 'cash'
if (incentive == 'cash') {
$incentive = $(this);
$offer = $incentive.find('cash\\:offer, offer');
$offerDescription = $offer.find('cash\\:description, description').text();
$offer.find('cash\\:disclaimers, disclaimers').each(function (i, v) {
console.log ("here executing" + $(i).find('cash\\:disclaimer, disclaimer').text() );
My console window prints out a blue little circle with the number 2 in it along with "here executing" and no value. Even if I use
$(this).find('cash\:disclaimers, disclaimers').each(function (i, v) { }) versus $offer.find('cash\:disclaimers, disclaimers').each(function (i, v) {
I get the same results in my console window. Any ideas or knowledge sharing would be greatly appreciate it.

Populate items into SELECT with Jquery

I'm having trouble populating a SELECT with jquery, when the user writes the zipcode or part of it, it searches the database and returns this:
{"success":1,"id":"50","street":"Central One"},{"success":1,"id":"60","street":"Central Two"}
One success for each street it finds. For a single street and using a text input I'm using this
UPDATE 1 - FULL CODE
$(document).ready( function() {
$('#zip').blur(function(){
$.ajax({
url : '../../controller/zip.php',
type : 'POST',
data: 'zip=' + $('#zip').val(),
dataType: 'json',
success: function(data){
if(data.sucesso == 1){
$('#id').val(data.id);
$('#street').val(data.street);
}
}
});
return false;
})
});
How can I change this so I can populate a select box.
Thanks
What is being passed back for a single address is a single object from which you can grab the information. When there are multiple responses you need to go through each of them and handle them.
When we look at MDN's article it shows that we need a parent <select> tag and then we need to populate the children. The process would look like this:
Find / create parent select
[Optional] Remove previous child <option> tags
Loop through responses
Create a new <option> element
Populate the <option> with the appropriate value and content
Append it to the parent <select>
Some things to be aware of, if you're clearing the previous addresses each time you get a response from the database you'll want to remove these previous <option>s. This can be done either by .empty() if there are no other children in the parent or starting with the parent <select> and removing all child <options>.
Use this for adding items to select box dynamically:
var $selectBox = $('#selectboxId');
$selectBox.empty();
$.each(data, function (idx, val) {
if (val.success) {
$selectBox.append($('<option>', {
value: val.id,
text: val.street
}));
}
});
I would not encourage to do so; you're better off using a html-templating engine like mustache or handlebars.
Doing this kind of stuff in plain JS (string concatenation) is gross. It pollutes your sourcecode.
Anyways, this would do the trick to generate the necessary HTML:
function generateHTML(data){
return data.reduce(function(o,n){
return o+"<option value='"+n.id+"'>"+n.street+"</option>";
},"");
}
Here is the Fiddle to play with. If you need to filter for success, you could add a filter()
function generateHTML(data){
return data.filter(function(x){
return !!x.success;
}).reduce(function(o,n){
return o+"<option value='"+n.id+"'>"+n.street+"</option>";
},"");
}
You could easily use $("#selectBoxId").html(generateHTML(data)) to insert it to the DOM.
To fit it into your codebase, you should add it in the success handler:
success: function(data){
function generateHTML(data){
return data.reduce(function(o,n){
return o+"<option value='"+n.id+"'>"+n.street+"</option>";
},"");
}
$("select").html(generateHTML(data))
}
For the inner workings of Array.prototype.reduce() take a look at MDN and for Array.prototype.filter()
If the JSON being returned is a list [{...}, ..., {...}], then you can use Array.forEach. Here is the success callback:
function(data) {
data.forEach(function(item) {
if (item.success) {
// use item.id and item.street
}
});
}
If you have a <select> element, then you will want to be populating it with <options>, by appending an <option> element under each successful "if" branch in the forEach.
Assuming you already have the select element on the page and the data that is coming back from the server is an array of objects, this should work:
$.ajax({
url : '../../controller/zip.php',
type : 'POST',
data: 'zip=' + $('#zip').val(),
dataType: 'json',
success: function(data) {
var $items = [];
$.each(data, function(street) {
if(data.success === 1) {
$items.push($('<option />').attr({
value: street.id
}).text(street.street));
}
});
$('#your-select-element').append($items);
}
});
Notice this isn't setting the value for one option, it is creating <option> tags for each of the response's streets and appending them to a <select> element.

Having issues tying together basic javascript chat page

I have the skeleton of a chat page but am having issues tying it all together. What I'm trying to do is have messages sent to the server whenever the user clicks send, and also, for the messages shown to update every 3 seconds. Any insights, tips, or general comments would be much appreciated.
Issues right now:
When I fetch, I append the <ul class="messages"></ul> but don't want to reappend messages I've already fetched.
Make sure my chatSend is working correctly but if I run chatSend, then chatFetch, I don't retrieve the message I sent.
var input1 = document.getElementById('input1'), sendbutton = document.getElementById('sendbutton');
function IsEmpty(){
if (input1.value){
sendbutton.removeAttribute('disabled');
} else {
sendbutton.setAttribute('disabled', '');
}
}
input1.onkeyup = IsEmpty;
function chatFetch(){
$.ajax({
url: "https://api.parse.com/1/classes/chats",
dataType: "json",
method: "GET",
success: function(data){
$(".messages").clear();
for(var key in data) {
for(var i in data[key]){
console.log(data[key][i])
$(".messages").append("<li>"+data[key][i].text+"</li>");
}
}
}
})
}
function chatSend(){
$.ajax({
type: "POST",
url: "https://api.parse.com/1/classes/chats",
data: JSON.stringify({text: $('input1.draft').val()}),
success:function(message){
}
})
}
chatFetch();
$("#sendbutton").on('click',chatSend());
This seems like a pretty good project for Knockout.js, especially if you want to make sure you're not re-appending messages you've already sent. Since the library was meant in no small part for that sort of thing, I think it would make sense to leverage it to its full potential. So let's say that your API already takes care of limiting how many messages have come back, searching for the right messages, etc., and focus strictly on the UI. We can start with our Javascript view model of a chat message...
function IM(msg) {
var self = this;
self.username = ko.observable();
self.message = ko.observable();
self.timestamp = ko.observable();
}
This is taking a few liberties and assuming that you get back an IM object which has the name of the user sending the message, and the content, as well as a timestamp for the message. Probably not too far fetched to hope you have access to these data elements, right? Moving on to the large view model encapsulating your IMs...
function vm() {
var self = this;
self.messages = ko.observableArray([]);
self.message = ko.observable(new IM());
self.setup = function () {
self.chatFetch();
self.message().username([user current username] || '');
};
self.chatFetch = function () {
$.getJSON("https://api.parse.com/1/classes/chats", function(results){
for(var key in data) {
// parse your incoming data to get whatever elements you
// can matching the IM view model here then assign it as
// per these examples as closely as possible
var im = new IM();
im.username(data[key][i].username || '');
im.message(data[key][i].message || '');
im.timestamp(data[key][i].message || '');
// the ([JSON data] || '') defaults the property to an
// empty strings so it fails gracefully when no data is
// available to assign to it
self.messages.push(im);
}
});
};
}
All right, so we have out Javascript models which will update the screen via bindings (more on that in a bit) and we're getting and populating data. But how do we update and send IMs? Well, remember that self.message object? We get to use it now.
function vm() {
// ... our setup and initial get code
self.chatSend = function () {
var data = {
'user': self.message().username(),
'text': self.message().message(),
'time': new Date()
};
$.post("https://api.parse.com/1/classes/chats", data, function(result) {
// do whatever you want with the results, if anything
});
// now we update our current messages and load new ones
self.chatFetch();
};
}
All right, so how do we keep track of all of this? Through the magic of bindings. Well, it's not magic, it's pretty intense Javascript inside Knockout.js that listens for changes and the updates the elements accordingly, but you don't have to worry about that. You can just worry about your HTML which should look like this...
<div id="chat">
<ul data-bind="foreach: messages">
<li>
<span data-bind="text: username"></span> :
<span data-bind="text: message"></span> [
<span data-bind="text: timestamp"></span> ]
</li>
</ul>
</div>
<div id="chatInput">
<input data-bind="value: message" type="text" placeholder="message..." />
<button data-bind="click: $root.chatSend()">Send</button>
<div>
Now for the final step to populate your bindings and keep them updated, is to call your view model and its methods...
$(document).ready(function () {
var imVM = new vm();
// perform your initial search and setup
imVM.setup();
// apply the bindings and hook it all together
ko.applyBindings(imVM.messages, $('#chat')[0]);
ko.applyBindings(imVM.message, $('#chatInput')[0]);
// and now update the form every three seconds
setInterval(function() { imVM.chatFetch(); }, 3000);
});
So this should give you a pretty decent start on a chat system in an HTML page. I'll leave the validation, styling, and prettifying as an exercise to the programmer...

Categories