Clearing last JSON response - javascript

I am developing an iOS 6.1 app using Titanium Studio, build: 3.1.2.201307091805, I am testing on the iPhone simulator and iPad device. I have a search field that gets JSON results from a remote server. The screen I am having issues with has the search box at the top and a couple of messages below. When the user types in the search field and hits return, the messages are hidden and a table is placed ready to receive the results from the database. All of that is working fine. When the user types in something that is not in the database I have a message appear "No results found, please try again". I made a button to "Clear" the table or "Not Found" message. Here is the button code I have so far:
var clear = Ti.UI.createButton({
title: "Clear",
style:Titanium.UI.iPhone.SystemButtonStyle.BORDERED
});
clear.addEventListener("click", function() {
message.hide();
table.setData([]);
});
Ti.UI.currentWindow.setRightNavButton(clear);
This code does clear the message or the results in the table but when I do another search the previous result appears above the new result even if the searches were totally unrelated. Here is my code.
var win = Titanium.UI.currentWindow;
win.backgroundImage='images/background.png';
win.barColor='#28517A';
win.title='Product Search';
var message = Ti.UI.createLabel({
text: 'No results found, please try again',
top:'100dp',
left:'20dp',
right:'20dp'
});
var customSearchBar = Ti.UI.createView({
backgroundColor: '#28517A',
height: 42,
top: '0dp',
width: Ti.UI.FILL
});
var customSearchField = Ti.UI.createTextField({
autocorrect: false,
borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED,
clearOnEdit: true,
height: 28,
hintText: 'Search For Product or Service',
textAlign: 'center',
width: '90%',
});
customSearchBar.add(customSearchField);
win.add(customSearchBar);
var nolist= Ti.UI.createLabel({
text: 'XXXXXX',
color: '#000',
font: {fontSize:'16dp', fontWeight:'bold'},
top:'50dp',
left:'20dp',
right:'20dp'
});
win.add(nolist);
var businessowner = Ti.UI.createLabel({
text: 'XXXXXX',
color: '#000',
font: {fontSize:'16dp', fontWeight:'bold'},
bottom:'10dp',
left:'20dp',
right:'20dp'
});
win.add(businessowner);
var view = Ti.UI.createView({
backgroundColor: 'transparent',
top: '100dp',
bottom:'60dp'
});
var table = Ti.UI.createTableView({
backgroundColor: 'transparent',
top: '0dp',
height:'auto',
bottom:'0dp'
});
view.add(table);
table.show();
var tableData = [];
function checkInternetConnection(){
return Ti.Network.online ? true : false;
}
customSearchField.addEventListener("return", function(e) {
if(checkInternetConnection()){
nolist.hide();
businessowner.hide();
getdata();
win.add(view);
function getdata(){
var url = "http://mydomain.com/filename.php?title="+e.value;
var xhr = Ti.Network.createHTTPClient({
onload: function() {
Ti.API.debug(this.responseText);
var json = JSON.parse(this.responseText);
if (json.cms_list.length< 1){
win.add(message);
}
for (i = 0; i < json.cms_list.length; i++) {
client = json.cms_list[i];
row = Ti.UI.createTableViewRow({
height:'44dp',
hasChild:true
});
var clientlist = Ti.UI.createLabel({
text:client.clientname,
font:{fontSize:'16dp', fontWeight:'bold'},
height:'auto',
left:'10dp',
color:'#000'
});
row.add(clientlist);
tableData.push(row);
}
table.addEventListener('click',function(e){
var row = e.row;
var clientlist = row.children[0];
var win = Ti.UI.createWindow({
url: 'clientdetail.js',
title: clientlist.text
});
var clientlist = clientlist.text;
win.clientlist = clientlist;
customSearchField.blur();
Titanium.UI.currentTab.open(win,{animated:true});});
table.setData(tableData);
},
onerror: function(e) {
Ti.API.debug("STATUS: " + this.status);
Ti.API.debug("TEXT: " + this.responseText);
Ti.API.debug("ERROR: " + e.error);
alert('There was an error retrieving the remote data. Try again.');
},
timeout:5000
});
xhr.open("GET", url);
xhr.send();
}
}
else{
alert('Your internet connection is not available');
}
});
var clear = Ti.UI.createButton({
title: "Clear",
style:Titanium.UI.iPhone.SystemButtonStyle.BORDERED
});
clear.addEventListener("click", function() {
message.hide();
table.setData([]);
});
Ti.UI.currentWindow.setRightNavButton(clear);
If I press my back button and then return to this screen, the search is fine. How can I completely clear the previous results without leaving the screen and then returning?

You are adding the table to the window every time you click "return". Change your event listener by removing win.add(view); from it, and replace that line with table.show(); like this:
customSearchField.addEventListener("return", function(e) {
if(checkInternetConnection()){
nolist.hide();
businessowner.hide();
getdata();
//win.add(view); dont do this!!!!
table.show();
.....
});
Then, change this:
var table = Ti.UI.createTableView({
backgroundColor: 'transparent',
top: '0dp',
height:'auto',
bottom:'0dp'
});
view.add(table);
//table.show();
win.add(table);
table.hide();
Now you will only have one instance of a table, and you can use setData inside the return listener every time you want to change all the rows.

You are not clearing data from var tabledata. It should be cleared when you are setting table.setData([]); . It is pushing the same data after setting the table as empty.
Your code should look like this:
clear.addEventListener("click", function() {
message.hide();
tableData = [];
table.setData([]);
});

Related

how to auto scroll down when new messages added

I am working with django , I want to scroll down auto when new messages added 'sent or received', I can scroll down auto when I refrech the page because of this code line :
$("#card-body").animate({ scrollTop: 20000000 }, "slow");
but when I send and I receive new messages the messages go down until I can't see them I have to scroll down manually
this is the js code :
<script>
/* send message*/
document.getElementById('send-btn-id').onclick = function (e) {
const msg = document.getElementById('message').value;
chatSocket.send(JSON.stringify({
'message': msg,
'user': me,
'friend': friendName
}));
document.getElementById('message').value = "";
};
const friendName = JSON.parse(document.getElementById('friend').textContent);
const me = JSON.parse(document.getElementById('me').textContent);
/* set friend profile name */
document.getElementById('friend-name').innerHTML = friendName['username'];
/* start conversation */
document.querySelector('.start-conversation').innerHTML = 'Start conversation with <strong>'+friendName['username']+'</strong>';
/* connection request */
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/chat/'
+ friendName['username']
+ '/'
);
chatSocket.onmessage = function (e) {
const data = JSON.parse(e.data);
var class_name = 'in';
var profile_image = '{{friend_obj.profile.image.url}}';
if(me['username'] == data.user['username']) {
data.user['username'] = 'Me';
class_name = 'out';
profile_image = '{{request.user.profile.image.url}}';
}
var chat_list = document.querySelector('#chat-list-id');
var chat = "<li class=\""+class_name+"\"><div class=\"chat-img\"><img alt=\"avatarchat\" src=\""+profile_image+"\"></div><div class=\"chat-body\"><div class=\"chat-message\"><h5>"+data.user['username']+"</h5><p>"+data.message+"</p></div></div></li>";
chat_list.innerHTML += chat;
};
</script>
If you want to do this easily, you can do the following:
window.scrollTo(0, document.body.scrollHeight);
Thanks to this post
WHAT YOU SHOULD NOT DO
window.scrollTo(0, 9999);
Even though the number is big, sometimes webpages can be VERY large.
BACK TO CONTENT
If you want it to scroll smoothly, then you can set this css property:
html {
scroll-behavior: smooth;
}
Working example:
const btmG = document.querySelector("#btm-good");
const btmB = document.querySelector("#btm-bad");
window.onload = () => {
btmG.onclick = () => {
window.scrollTo(0, document.body.scrollHeight);
};
btmB.onclick = () => {
window.scrollTo(0, 9999);
};
}
html {
scroll-behavior: smooth;
}
<button id="btm-good"> Scroll to bottom (not 9999) </button>
<button id="btm-bad"> Scroll to bottom (is 9999) </button>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>Wait a sec, this isn't the bottom...<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
Hi
hello guys thanks to you I have found the solution and I want to share it with you and it works actually,so really thank you :
I thought that I can actually make this code line in the send, hold on you will understand after watching the code :
I have mentioned this before right
$("#card-body").animate({ scrollTop: 20000000 }, "slow");
and this one either :
/* send message*/
document.getElementById('send-btn-id').onclick = function (e) {
const msg = document.getElementById('message').value;
chatSocket.send(JSON.stringify({
'message': msg,
'user': me,
'friend': friendName
}));
document.getElementById('message').value = "";
};
so after watching your answers I think to put the line in the //send message like this :
/* send message*/
document.getElementById('send-btn-id').onclick = function (e) {
const msg = document.getElementById('message').value;
chatSocket.send(JSON.stringify({
'message': msg,
'user': me,
'friend': friendName
}));
document.getElementById('message').value = "";
$("#card-body").animate({ scrollTop: 20000000 }, "slow");
};
my english is not fine but the code works, I hope it helps someone facing same problem.

Stripe token not generating when using a live Publiashable Key

I am building a custom checkout where Stripe is handling the payment information. I'm using the Stripe Elements Library. When I was using the test publishable key I was about to get an input with a token but once I switched to the live key that was no longer happening. I'm not sure if there something missing in my setup that's not allowing the token to be generated when the live key is active.
Here's my Javascript for the Stripe Elements integrations
<script src="https://js.stripe.com/v3/"></script>
<script>
// Create a Stripe client.
var stripe = Stripe('pk_live_xxxxxxxxxxxxxx');
// Create an instance of Elements.
var elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide below.)
var style = {
base: {
color: '#32325d',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
},
':focus': {
color: '#333',
},
'::placeholder': {
color: '#333',
},
':focus::placeholder': {
color: '#333',
},
},
invalid: {
color: '#DC5B5B',
iconColor: '#DC5B5B',
':focus': {
color: '#DC5B5B',
},
'::placeholder': {
color: '#DC5B5B',
},
}
};
var elementClasses = {
focus: 'focus',
empty: 'empty',
invalid: 'invalid',
};
// Create an instance of the card Element.
var cardNumber = elements.create('cardNumber', {
style: style,
classes: elementClasses,
});
cardNumber.mount('#example3-card-number');
var cardExpiry = elements.create('cardExpiry', {
style: style,
classes: elementClasses,
});
cardExpiry.mount('#example3-card-expiry');
var cardCvc = elements.create('cardCvc', {
style: style,
classes: elementClasses,
});
cardCvc.mount('#example3-card-cvc');
registerElements([cardNumber, cardExpiry, cardCvc], 'example3');
function registerElements(elements, exampleName) {
var formClass = '.' + exampleName;
var example = document.querySelector(formClass);
var form = example.querySelector('form');
var resetButton = example.querySelector('a.reset');
var error = form.querySelector('.error');
var errorMessage = error.querySelector('.message');
function enableInputs() {
Array.prototype.forEach.call(
form.querySelectorAll(
"input[type='text'], input[type='email'], input[type='tel']"
),
function(input) {
input.removeAttribute('disabled');
}
);
}
function disableInputs() {
Array.prototype.forEach.call(
form.querySelectorAll(
"input[type='text'], input[type='email'], input[type='tel']"
),
function(input) {
input.setAttribute('disabled', 'true');
}
);
}
function triggerBrowserValidation() {
// The only way to trigger HTML5 form validation UI is to fake a user submit
// event.
var submit = document.createElement('input');
submit.type = 'submit';
submit.style.display = 'none';
form.appendChild(submit);
submit.click();
submit.remove();
}
// Listen for errors from each Element, and show error messages in the UI.
var savedErrors = {};
elements.forEach(function(element, idx) {
element.on('change', function(event) {
if (event.error) {
error.classList.add('visible');
savedErrors[idx] = event.error.message;
errorMessage.innerText = event.error.message;
} else {
savedErrors[idx] = null;
// Loop over the saved errors and find the first one, if any.
var nextError = Object.keys(savedErrors)
.sort()
.reduce(function(maybeFoundError, key) {
return maybeFoundError || savedErrors[key];
}, null);
error.classList.remove('visible');
if (nextError) {
// Now that they've fixed the current error, show another one.
errorMessage.innerText = nextError;
error.classList.add('visible');
} else {
// The user fixed the last error; no more errors.
error.classList.remove('visible');
}
}
});
});
// Listen on the form's 'submit' handler...
form.addEventListener('submit', function(e) {
e.preventDefault();
// Trigger HTML5 validation UI on the form if any of the inputs fail
// validation.
var plainInputsValid = true;
Array.prototype.forEach.call(form.querySelectorAll('input'), function(
input
) {
if (input.checkValidity && !input.checkValidity()) {
plainInputsValid = false;
return;
}
});
if (!plainInputsValid) {
triggerBrowserValidation();
return;
}
// Show a loading screen...
example.classList.add('submitting');
// Disable all inputs.
disableInputs();
// Gather additional customer data we may have collected in our form.
var name = form.querySelector('#' + exampleName + '-name');
var address1 = form.querySelector('#' + exampleName + '-address');
var city = form.querySelector('#' + exampleName + '-city');
var state = form.querySelector('#' + exampleName + '-state');
var zip = form.querySelector('#' + exampleName + '-zip');
var additionalData = {
name: name ? name.value : undefined,
address_line1: address1 ? address1.value : undefined,
address_city: city ? city.value : undefined,
address_state: state ? state.value : undefined,
address_zip: zip ? zip.value : undefined,
};
// Use Stripe.js to create a token. We only need to pass in one Element
// from the Element group in order to create a token. We can also pass
// in the additional customer data we collected in our form.
stripe.createToken(elements[0], additionalData).then(function(result) {
// Stop loading!
example.classList.remove('submitting');
if (result.token) {
stripeTokenHandler(result.token)
} else {
// Otherwise, un-disable inputs.
enableInputs();
}
});
});
}
// Submit the form with the token ID.
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
}
I only made minor changes to the Javascript code above to match my html when I first implemented it other than that the code is exactly what I found and used when I had the test key.
I'm not very familar with Stripe's Element Library so any help would be greatly appreciated.

Communication between browser tabs: page titles must be updated synchronously for all browser tabs

what i have: page title is updating dynamically when new data is retrieving from ajax call; if tab with this page is visited - title is set to default value; if i open the second tab with this page, title of this tab is set to default (i must fix this)
what i need: page title must be the same for all tabs with this page. i mean, page title must be updated synchronously for all tabs.
My current implementation:
var prevData;
var newRequestsCounter = 0
var getRequests = function(){
$.ajax({
async: true,
type: "GET",
url: "/get_requests/",
success: function(data){
// retrieve and parse data. i skip this part
// newRequestsCounter is updating here
var visible = vis();
if (visible){
newRequestsCounter = 0
document.title = 'Default title'
} else {
if (newRequestsCounter == 0) {
document.title = 'Default title'
} else {
document.title = 'Dynamic title'
}
}
setTimeout(getRequests, 2000)
}
});
};
I tried with intercom.js, but it doesn't work properly. For some reason intercom.on gets different data each time. For example: first call - default title, second call - dynamic title. I checked with debug, wrong data comes after executing this line setTimeout(getRequests, 2000).
var intercom = Intercom.getInstance();
intercom.on('notice', function(data) {
document.title = data.title;
});
var prevData;
var newRequestsCounter = 0
var getRequests = function(){
$.ajax({
async: true,
type: "GET",
url: "/get_requests/",
success: function(data){
// retrieve and parse data. i skip this part
// newRequestsCounter is updating here
var visible = vis();
if (visible){
newRequestsCounter = 0
intercom.emit('notice', {title: 'Default title'});
} else {
if (newRequestsCounter == 0) {
intercom.emit('notice', {title: 'Default title'});
} else {
intercom.emit('notice', {title: 'Dynamic title'});
}
}
setTimeout(getRequests, 2000)
}
});
};
In general, i don't quite understand if it possible to achieve required functionality in scope of single ajax callback. I tried the next code. In this case variable "counter" from localStorage is incremented every time i open new tab. It means if i expect "3" in title for two tabs, i get "6" with two tabs instead.
var intercom = Intercom.getInstance();
intercom.on('notice', function(data) {
document.title = data.title;
});
if (localStorage.getItem("counter") === null){
localStorage.setItem("counter", 0);
}
var getRequests = function(){
$.ajax({
async: true,
type: "GET",
url: "/get_requests/",
success: function(data){
// skip part with retrieving and parsing data
var counter = localStorage.getItem("counter")
localStorage.setItem("counter", ++counter);
var visible = vis();
if (visible){
localStorage.setItem("counter", 0);
intercom.emit('notice', {title: 'Default'});
} else {
if (localStorage.getItem("counter") == 0 || localStorage.getItem("counter") === null) {
intercom.emit('notice', {title: 'Default'});
} else {
intercom.emit('notice', {title: '(' + localStorage.getItem("counter") + ') requests'});
}
}
setTimeout(getRequests, 2000)
}
});
};
getRequests();
The part I am not understanding in your code is where you are opening a new browser tab. But, if that happening somewhere and you want to set the title of that new tab as its opening you can do this:
var newTab = window.open('/page')
newTab.title = 'New Title';
are you using some kind of long polling?
Maybe you can synchronise those polling calls with the browser's time.
e.g. poll everytime the browser's time's seconds are even numbers. then each tab should send its request at the same time and get (almost) at the same time an answer to update there title

DialogBox to show when you click a button with JavaScript

I'm having problem connecting my Dialog box with a clickable button. I want to show a dialogbox when I click a button but unfortunately, I can't do the function very well. This is my code, I know its really bad and I need some idea or a hand:
define: function () {
var dialog = new Ext.LayoutDialog('test', {
modal: true;
height: 500;
width: 500;)
};
var button = new Ext.Button("btn", {
text: "検索実行",
handler: this.showdialog.createDelegate(this)
});
}
},
I think, when creating an Ext.LayoutDialog, the id that will be used should be taken from a div tag then you'll simply add the method, addButton, so that the layoutdialog will have buttons. Don't use semicolons when adding configurations to the layoutdialog, you'll only use commas then the last config should no longer have a comma. Visit this link to know more about ext >> http://dev.sencha.com/deploy/ext-1.1.1/docs/ :)
var sample = Class.create();
sample.prototype = {
initialize: function () {
this.define();
}
define: function () {
var createDialog = function () {
var dialog = new Ext.LayoutDialog('test', {
modal: true,
height: 500,
width: 500,
center: {
autoscroll: true
}
});
button = dialog.addButton({ text: "検索実行" });
button.on('click', function() {
//name of the dialog that you want to display
showdialog.show();
});
var layout = dialog.getLayout();
layout.beginUpdate();
var center = layout.getRegion('center');
center.add(new Ext.ContentPanel("test", { titlebar: false }));
layout.endUpdate();
}
}
}

Open new window from TableView in Titanium Mobile

i create some application in titanium mobile for opening a window when a row in TableView is clicked by user..
here's my code:
Menu.js
function Menu() {
Titanium.UI.setBackgroundColor('#000');
var masterMenu = Titanium.UI.createTabGroup();
var winMenu1 = Titanium.UI.createWindow({
title:'Menu 1',
backgroundColor:'#fff'
});
var tabMenu1 = Titanium.UI.createTab({
icon:'KS_nav_views.png',
title:'Menu 1',
window:winMenu1
});
var menuData1 = [
{title: 'Account', url: 'Account.js'},
{title: 'Meetings', url: 'Meetings.js'}
];
var menuList1 = Ti.UI.createTableView({
data: menuData1
});
menuList1.addEventListener('click', function(e) {
var newWindow = Titanium.UI.createWindow({
url:e.rowData.url,
title:e.rowData.title
});
newWindow.open({
animated:true
});
});
winMenu1.add(menuList1);
var winMenu2 = Titanium.UI.createWindow({
title:'Menu 2',
backgroundColor:'#fff'
});
var tabMenu2 = Titanium.UI.createTab({
icon:'KS_nav_ui.png',
title:'Menu 2',
window:winMenu2
});
masterMenu.addTab(tabMenu1);
masterMenu.addTab(tabMenu2);
return masterMenu;
}
module.exports = Menu;
when some row is clicked by user, it will redirect and open new window based on url on the menuData1. for example i clicked Account row, and it should be redirected to Account.js. Here's my Account.js code :
var win = Ti.UI.currentWindow;
var label1 = Titanium.UI.createLabel({
color:'#999',
text:'Close',
font:{fontSize:20,fontFamily:'Helvetica Neue'},
textAlign:'center',
width:'auto'
});
label1.addEventListener('click', function() {
win.close();
});
win.add(label1);
The main problem is label1 in Account.js not opened in new window but shown in menu list.
Does anyone know how to open Account.js in new window?? thanks before..
Try to set backgroundColor for your window:
menuList1.addEventListener('click', function(e) {
var newWindow = Titanium.UI.createWindow({
backgroundColor: '#fff',
url:e.rowData.url,
title:e.rowData.title
});
newWindow.open({
animated:true
});
});

Categories