Grails non null params reaching controller as null? - javascript

I am having some trouble trying to get params from my GSP to my controller from a Javascript click handler that looks like this:
$('#save').click(function () {
var uniqueId = "${recordToEdit.uniqueId}";
var secondaryId = "${recordToEdit.secondaryId}";
console.log(removedYellowIssues);
<g:remoteFunction controller="customer"
action="saveModifiedIndividualRecord"
params='{uniqueId: uniqueId,
secondaryId: secondaryId,
yellowIssuesRemoved: removedYellowIssues,
redIssuesRemoved: removedRedIssues}'/>
});
When the "save" button is pressed this is what I see in the javascript console:
["No address provided."]
so you can see the the 'removedYellowIssues' list is NOT empty. It's a Javascript list containing one string. However, here is what my controller thinks:
<><><> Parameters ***:
<><><> uniqueId: 239400B
<><><> secondaryId: 1
<><><> Red issues removed: null
<><><> Yellow issues removed: null
Here is the controller action:
def saveModifiedIndividualRecord() {
println "<><><> Parameters ***: "
println "<><><> uniqueId: " + params.uniqueId
println "<><><> secondaryId: " + params.secondaryId
println "<><><> Red issues removed: " + params.redIssuesRemoved
println "<><><> Yellow issues removed: " + params.yellowIssuesRemoved
}
Here is more of the Javascript code containing the above save button snippet.
var currentYellowIndex = 0;
var allYellowIssues = $('#allYellowIssues'); // The unordered list 'ul'
var removedYellowIssues = []; // An array to keep track of issues removed
if (allYellowIssues.length) { // If there are issues to be displayed
var yellowElements = document.getElementsByName('yellowIssue');
var yellowListSize = yellowElements.length;
yellowElements[currentYellowIndex].className = "display";
$('#yellowStartIndex').html(currentYellowIndex + 1);
$('#yellowSizeIndex').html(yellowListSize);
$('#nextYellowIssue').click(function () {
if (currentYellowIndex < yellowListSize-1) {
yellowElements[currentYellowIndex++].className = "display-none";
yellowElements[currentYellowIndex].className = "display";
$('#yellowStartIndex').html(currentYellowIndex + 1);
}
});
$('#previousYellowIssue').click(function () {
if (currentYellowIndex > 0) {
yellowElements[currentYellowIndex--].className = "display-none";
yellowElements[currentYellowIndex].className = "display";
$('#yellowStartIndex').html(currentYellowIndex + 1);
}
});
$('#clearYellowFlag').click(function () {
removedYellowIssues.push(yellowElements[currentYellowIndex].innerHTML);
yellowElements[currentYellowIndex].className = "display-none";
yellowElements[currentYellowIndex].remove();
yellowListSize = yellowElements.length;
if (yellowListSize == 0)
$('#yellowIssues').hide();
else {
currentYellowIndex = 0;
yellowElements[currentYellowIndex].className = "display";
$('#yellowStartIndex').html(currentYellowIndex + 1);
$('#yellowSizeIndex').html(yellowListSize);
}
});
}
$('#save').click(function () {
var uniqueId = "${recordToEdit.uniqueId}";
var secondaryId = "${recordToEdit.secondaryId}";
console.log(removedYellowIssues);
<g:remoteFunction controller="customer"
action="saveModifiedIndividualRecord"
params='{uniqueId: uniqueId,
secondaryId: secondaryId,
yellowIssuesRemoved: removedYellowIssues,
redIssuesRemoved: removedRedIssues}'/>
});
The last part of the GSP is where the save button itself is defined as follows:
<br>
<button id="save"> Save </button>&nbsp&nbsp&nbsp
<button id="cancel" class="close" type="button"> Cancel </button>

I feel like the { } in the params should be [ ] instead. The g:remoteFunction is a GSP tag and the params should be a map.
<g:remoteFunction controller="customer"
action="saveModifiedIndividualRecord"
params='[uniqueId: uniqueId,
secondaryId: secondaryId,
yellowIssuesRemoved: removedYellowIssues,
redIssuesRemoved: removedRedIssues]'/>
However, you really shouldn't use that tag (I think it is deprecated in the latest versions). You should just do an a post via jQuery:
$.post("${g.createLink(action: 'saveModifiedIndividualRecord')", {uniqueId: uniqueId, ...}, function(result) {
...
});

Related

JS/jQ make a URL builder function without duplicate

First I should say, I just want to solve this as logic, not my real code is jQuery or JavaScript, because I learning reactjs I trying to solve this logic with jQ or JS then do it in React. So I don't want a solution like $.param and also don't want to replace last & with something, I looking for to make a URL Builder function, What I trying to do is add URL parameter (Query String) What I tried so far is:
let obj = {}
let array = []
let url = 'http://www.example.com/foo';
function buildUrl(base, key, value) {
var sep = (base.indexOf('?') > -1) ? '&' : '?';
return base + sep + key + '=' + value;
}
$('#btn1').click(function() {
obj = {
name: 'province',
value: 11
}
array.push(obj)
console.log('param 1 added!')
});
$('#btn2').click(function() {
obj = {
name: 'city',
value: 2
}
array.push(obj)
console.log('param 2 added!')
});
$('#build').click(function() {
$.each(array, function(i, v) {
url = buildUrl(url, v.name, v.value);
});
console.log(url)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btn1">1. Click this</button>
<kbd>-></kbd>
<button id="btn2">2. Then click this</button>
<kbd>=</kbd>
<button id="build">Make URL</button>
Somehow, it add province twice, I don't how to make this function to avoid duplicate parameters, any idea?
side note: I have many btn to build parameter, so I can't detect value each time!
It is all here and here
let url = new URL('http://www.example.com/foo');
let params = url.searchParams;
document.getElementById("buts").addEventListener('click', (e) => {
const tgt = e.target;
if (tgt.classList.contains('add')) {
params.set(tgt.id, tgt.getAttribute('data-value'));
console.log('param ' + tgt.id + ' added!', params.toString())
}
});
document.getElementById("build").addEventListener('click', (e) => console.log(url));
<div id="buts">
<button class="add" id="province" data-value="11">1. Click this</button>
<kbd>-></kbd>
<button class="add" id="city" data-value="2">2. Then click this</button>
<kbd>=</kbd>
<button id="build">Make URL</button>
</div>

Firebase - Prevent child_added when delete with limitToLast

i want to build mini webchat - When view site i set show 5 messages and if view more, you can click button. All things are fine but when i remove 1 node, firebase auto add last node into, how can i prevent it?
Ex: I have node A,B,C,D,E,F,G. I had loaded list C,D,E,F,G but when i delete 1 in all, it auto add B into list.
<div id="messgesDiv">
<center><h3>Message</h3></center>
</div>
<div style="margin-top: 20px;">
<input type="text" id="nameInput" placeholder="Name">
<input type="text" id="messageInput" placeholder="Message" data-id="">
<input type="text" id="idproject" placeholder="ID Project">
</div>
<button id="delete">Delete Test</button>
<button id="edit">Edit</button>
<button id="loadmore">Load more</button>
<button id="showlastkey">Show last key</button>
My javascript
$('#loadmore').click(function() {
i = 0; old = first;
myDataRef.orderByKey().endAt(first).limitToLast(6).on('child_added', function (snapshot){
if( i == 0)
first = snapshot.key();
var message = snapshot.val();
if(snapshot.key() != old)
displayChatMessage(message.name, message.text, message.idproject, 'old');
i++;
console.log('myDataRef.orderByKey().endAt(first).limitToLast(6)');
});
});
$("#messageInput").keypress(function (e){
if(e.keyCode == 13){ //Enter
var name = $("#nameInput").val();
var text = $("#messageInput").val();
var idproject = $("#idproject").val();
if($("#messageInput").data("id")=='')
{
myDataRef.push({name: name, text: text, idproject: idproject});
}
else
{
myDataRef.child(key).update({name: name, text: text, idproject: idproject});
$('#messageInput').attr('data-id', '');
}
$("#messageInput").val("");
}
});
myDataRef.limitToLast(5).on('child_added', function (snapshot){
if( i == 0)
first = snapshot.key();
var message = snapshot.val();
displayChatMessage(snapshot.key(), message.name, message.text, message.idproject, 'new');
i++;
console.log(snapshot.key());
console.log(' myDataRef.limitToLast(5)');
});
function displayChatMessage(key, name, text, idproject, status){
//console.log(name + " -- " + text + " -- " +idproject);
if( status == 'new')
{
$('<div/>', { 'data-id': key , 'class' : 'test'}).text(text + " - ").prepend($('<em/>').text(name+": " )).append("IdProject: "+idproject).appendTo($("#messgesDiv"));
$("#messgesDiv")[0].scrollTop = $("#messgesDiv")[0].scrollHeight;
}
else
{
$('<div/>', { 'data-id': key , 'class' : 'test'}).text(text + " - ").prepend($('<em/>').text(name+": " )).append("IdProject: "+idproject).insertAfter($("center"));
$("#messgesDiv")[0].scrollTop = $("#messgesDiv")[0].scrollHeight;
}
}
$('#delete').click(function() {
myDataRef.child(key).remove();
$('#messgesDiv').filter('[data-id="'+key+'"]').remove();
});
Firebase limit queries act like a view on top of the data. So if you create a query for the 5 most recent messages, the Firebase client will ensure that you always have the 5 most recent messages.
Say you start with these messages:
message1
message2
message3
message4
message5
Now if you add a message6, you will get:
child_removed message1
child_added message6
So that your total local view becomes:
message2
message3
message4
message5
message6
Conversely when you remove message 6 again, you get these events:
child_removed message6
child_added message1 (before message2)
So that you can update the UI and end up with the correct list again.
There is no way to change this behavior of the API. So if you want to handle the situation differently, you will have to do this in your client-side code.
Your code currently only handles child_added. If you have add a handler for child_removed you'll see that you can easily keep the user interface in sync with the data.
Alternatively you can detect that the message is already in your UI by comparing the key of the message you're adding to the ones already present in the DOM:
function displayChatMessage(key, name, text, idproject, status){
var exists = $("div[data-id='" + key + "']").length;
if (status == 'new' && !exists) {
$('<div/>', { 'data-id': key , 'class' : 'test'}).text(text + " - ").prepend($('<em/>').text(name+": " )).append("IdProject: "+idproject).appendTo($("#messgesDiv"));
$("#messgesDiv")[0].scrollTop = $("#messgesDiv")[0].scrollHeight;
}
else {
$('<div/>', { 'data-id': key , 'class' : 'test'}).text(text + " - ").prepend($('<em/>').text(name+": " )).append("IdProject: "+idproject).insertAfter($("center"));
$("#messgesDiv")[0].scrollTop = $("#messgesDiv")[0].scrollHeight;
}
}

Couldn't append span element to array object in Angularjs/Jquery

Am struggling hard to bind an array object with list of span values using watcher in Angularjs.
It is partially working, when i input span elements, an array automatically gets created for each span and when I remove any span element -> respective row from the existing array gets deleted and all the other rows gets realigned correctly(without disturbing the value and name).
The problem is when I remove a span element and reenter it using my input text, it is not getting added to my array. So, after removing one span element, and enter any new element - these new values are not getting appended to my array.
DemoCode fiddle link
What am I missing in my code?
How can I get reinserted spans to be appended to the existing array object without disturbing the values of leftover rows (name and values of array)?
Please note that values will get changed any time as per a chart.
This is the code am using:
<script>
function rdCtrl($scope) {
$scope.dataset_v1 = {};
$scope.dataset_wc = {};
$scope.$watch('dataset_wc', function (newVal) {
//alert('columns changed :: ' + JSON.stringify($scope.dataset_wc, null, 2));
$('#status').html(JSON.stringify($scope.dataset_wc));
}, true);
$(function () {
$('#tags input').on('focusout', function () {
var txt = this.value.replace(/[^a-zA-Z0-9\+\-\.\#]/g, ''); // allowed characters
if (txt) {
//alert(txt);
$(this).before('<span class="tag">' + txt.toLowerCase() + '</span>');
var div = $("#tags");
var spans = div.find("span");
spans.each(function (i, elem) { // loop over each spans
$scope.dataset_v1["d" + i] = { // add the key for each object results in "d0, d1..n"
id: i, // gives the id as "0,1,2.....n"
name: $(elem).text(), // push the text of the span in the loop
value: 3
}
});
$("#assign").click();
}
this.value = "";
}).on('keyup', function (e) {
// if: comma,enter (delimit more keyCodes with | pipe)
if (/(188|13)/.test(e.which)) $(this).focusout();
if ($('#tags span').length == 7) {
document.getElementById('inptags').style.display = 'none';
}
});
$('#tags').on('click', '.tag', function () {
var tagrm = this.innerHTML;
sk1 = $scope.dataset_wc;
removeparent(sk1);
filter($scope.dataset_v1, tagrm, 0);
$(this).remove();
document.getElementById('inptags').style.display = 'block';
$("#assign").click();
});
});
$scope.assign = function () {
$scope.dataset_wc = $scope.dataset_v1;
};
function filter(arr, m, i) {
if (i < arr.length) {
if (arr[i].name === m) {
arr.splice(i, 1);
arr.forEach(function (val, index) {
val.id = index
});
return arr
} else {
return filter(arr, m, i + 1)
}
} else {
return m + " not found in array"
}
}
function removeparent(d1)
{
dataset = d1;
d_sk = [];
Object.keys(dataset).forEach(function (key) {
// Get the value from the object
var value = dataset[key].value;
d_sk.push(dataset[key]);
});
$scope.dataset_v1 = d_sk;
}
}
</script>
Am giving another try, checking my luck on SO... I tried using another object to track the data while appending, but found difficult.
You should be using the scope as a way to bridge the full array and the tags. use ng-repeat to show the tags, and use the input model to push it into the main array that's showing the tags. I got it started for you here: http://jsfiddle.net/d5ah88mh/9/
function rdCtrl($scope){
$scope.dataset = [];
$scope.inputVal = "";
$scope.removeData = function(index){
$scope.dataset.splice(index, 1);
redoIndexes($scope.dataset);
}
$scope.addToData = function(){
$scope.dataset.push(
{"id": $scope.dataset.length+1,
"name": $scope.inputVal,
"value": 3}
);
$scope.inputVal = "";
redoIndexes($scope.dataset);
}
function redoIndexes(dataset){
for(i=0; i<dataset.length; i++){
$scope.dataset[i].id = i;
}
}
}
<div ng-app>
<div ng-controller="rdCtrl">
<div id="tags" style="border:none;width:370px;margin-left:300px;">
<span class="tag" style="padding:10px;background-color:#808080;margin-left:10px;margin-right:10px;" ng-repeat="data in dataset" id="4" ng-click="removeData($index)">{{data.name}}</span>
<div>
<input type="text" style="margin-left:-5px;" id="inptags" value="" placeholder="Add ur 5 main categories (enter ,)" ng-model="inputVal" />
<button type="submit" ng-click="addToData()">Submit</button>
<img src="../../../static/app/img/accept.png" ng-click="assign()" id="assign" style="cursor:pointer;display:none" />
</div>
</div>
<div id="status" style="margin-top:100px;"></div>
</div>
</div>

Remove node function on parent element

I'm new to JS. I'm trying to delete the parent node with all the children by clicking a button. But the console tells me that undefined is not a function. What am I missing?
Fiddle:
http://jsfiddle.net/vy0d8bqt/
HTML:
<button type="button" id="output">Get contacts</button>
<button type="button" id="clear_contacts">clear contact</button>
<div id="output_here"></div>
JS:
// contact book, getting data from JSON and outputting via a button
// define a JSON structure
var contacts = {
"friends" :
[
{
"name" : "name1",
"surname" : "surname1"
},
{
"name" : "name2",
"surname" : "surname2"
}
]
};
//get button ID and id of div where content will be shown
var get_contacts_btn = document.getElementById("output");
var output = document.getElementById("output_here");
var clear = document.getElementById("clear_contacts");
var i;
// get length of JSON
var contacts_length = contacts.friends.length;
get_contacts_btn.addEventListener('click', function(){
//console.log("clicked");
for(i = 0; i < contacts_length; i++){
var data = contacts.friends[i];
var name = data.name;
var surname = data.surname;
output.style.display = 'block';
output.innerHTML += "<p> name: " + name + "| surname: " + surname + "</p>";
}
});
//get Children of output div to remove them on clear button
//get output to clear
output_to_clear = document.getElementById("output_here");
clear.addEventListener('click', function(){
output_to_clear.removeNode(true);
});
You should use remove() instead of removeNode()
http://jsfiddle.net/vy0d8bqt/1/
However, this also removes the output_to_clear node itself. You can use output_to_clear.innerHTML = '' if you like to just delete all content of the node, but not removing the node itself (so you can click 'get contacts' button again after clearing it)
http://jsfiddle.net/vy0d8bqt/3/
You want this for broad support:
output_to_clear.parentNode.removeChild(output_to_clear);
Or this in modern browsers only:
output_to_clear.remove();
But either way, make sure you don't try to remove it after it has already been removed. Since you're caching the reference, that could be an issue, so this may be safer:
if (output_to_clear.parentNode != null) {
output_to_clear.remove();
}
If you were hoping to empty its content, then do this:
while (output_to_clear.firstChild) {
output_to_clear.removeChild(output_to_clear.firstChild);
}
I think using jQuery's $.remove() is probably the best choice here. If you can't or don't want to use jQuery, The Mozilla docs for Node provides a function to remove all child nodes.
Element.prototype.removeAll = function () {
while (this.firstChild) { this.removeChild(this.firstChild); }
return this;
};
Which you would use like:
output_to_clear.removeAll();
For a one-off given the example provided:
while (output_to_clear.firstChild) { output_to_clear.removeChild(output_to_clear.firstChild); }

Date entries in the array are not printed

I've just created an dynamic HTML form and two of its fields are of type date. Those two fields are posting their data into two arrays. I have 2 issues:
a) The array data are not printed when I press the button.
b) Since I created the arrays to store the data, my dynamic form doesn't seem to be fully functional. It only produces new fields when I press the first "Save entry" button on the form. It also doesn't delete any fields.
My code is:
$(document).ready(function () {
$('#btnAdd').click(function () {
var $address = $('#address');
var num = $('.clonedAddress').length;
var newNum = new Number(num + 1);
var newElem = $address.clone().attr('id', 'address' + newNum).addClass('clonedAddress');
newElem.children('div').each(function (i) {
this.id = 'input' + (newNum * 10 + i);
});
newElem.find('input').each(function () {
this.id = this.id + newNum;
this.name = this.name + newNum;
});
if (num > 0) {
$('.clonedAddress:last').after(newElem);
} else {
$address.after(newElem);
}
$('#btnDel').removeAttr('disabled');
});
$('#btnDel').click(function () {
$('.clonedAddress:last').remove();
$('#btnAdd').removeAttr('disabled');
if ($('.clonedAddress').length == 0) {
$('#btnDel').attr('disabled', 'disabled');
}
});
$('#btnDel').attr('disabled', 'disabled');
});
$(function () {
$("#datepicker1").datepicker({
dateFormat: "yy-mm-dd"
}).datepicker("setDate", "0");
});
var startDateArray = new Array();
var endDateArray = new Array();
function intertDates() {
var inputs = document.getElementsById('datepicker1').value;
var inputsend = document.getElementsById('datepicker2').value;
startDateArray[startDateArray.length] = inputs;
endDateArray[endDateArray.length] = inputsend;
window.alert("Entries added!");
}
function show() {
var content = "<b>Elements of the arrays:</b><br>";
for (var i = 0; i < startDateArray.length; i++) {
content += startDateArray[i] + "<br>";
}
for (var i = 0; i < endDateArray.length; i++) {
content += endDateArray[i] + "<br>";
}
}
JSFIDDLE
Any ideas? Thanks.
On your button you are using element ID's several times, this is so wrong, IDs must be unique for each element, for example:
<button id="btnAdd" onclick="insertDates()">Save entry</button>
</div>
</div>
<button id="btnAdd">Add Address</button>
<button id="btnDel">Delete Address</button>
jQuery will attach the $('#btnAdd') event only on the first #btnAdd it finds.
You need to use classes to attach similar events to multiple elements, and in addition to that simply change all the .click handlers to .on('click', because the on() directive appends the function to present and future elements where as .click() only does on the existing elements when the page is loaded.
For example:
<button id="btnDel">Delete Address</button>
$('#btnDel').click(function () {
[...]
});
Becomes:
<button class="btnDel">Delete Address</button>
$('.btnDel').on('click', function () {
[...]
});
Try this : I know its not answer but it's wrong to get element value using id
Replace
var inputs = document.getElementsById('datepicker1').value;
var inputsend = document.getElementsById('datepicker2').value;
With
var inputs = document.getElementById('datepicker1').value;
var inputsend = document.getElementById('datepicker2').value;
You are using jQuery so i will strongly recommend you to stick with the jQuery selector,
var inputs = $('#datepicker1').val();
var inputsend = $('#datepicker2').val();
where # is used for ID selector.

Categories

Resources