I've got a single page application inside of my larger application that will send data to the DB, and will also display that same table's data. Currently, I have AJAX dynamically sending the data. However, to get the data just inserted to appear in the table that I want it to, I have to refresh. I've been trying things all morning, but below is the current state of things.
The View:
<html>
<head>
<!--I took some stuff out to make it easier to look at -->
</head>
<body onresize="resizeRecalc()">
<div class="container-fluid">
<div class="row header">
<div class="col-12">
<img src="{{ URL::asset('images/takeStatsLogo.png') }}" id="header-logo" />
</div>
</div>
<div class="mainArea row">
<div class="left col-8">
<div onclick="playPause()" class="embed-responsive embed-responsive-16by9">
<video id="gameFilm" src="{{ URL::asset('images/basketball.mp4') }}" preload="metadata"></video>
</div>
<div class="timebar">
<span class="timeItem" id="timestamp"></span>
<div onclick="changeVidTime()" onmousemove="moveLine(event)" onmouseout="REmoveLine()" id="outerBox"> <div id="progressBox"> <div id="placeMarker">
</div></div></div>
<span class="timeItem" id="duration-place"></span>
</div>
<!-- This is a key part -->
<div id="statList">
#include('partials.statList')
</div>
</div>
<div id="right" class="right col-4">
<!--Checking if we should make the user select starters. If we have them, no need to do that...-->
#if ($game->starters != null)
#include('partials.areStarters')
#else
#include('partials.noStarters')
#endif
</div>
</div>
</div>
<script>
//Add Stat Form
//This part here will add the stats, but it won't refresh them!
$('input#addStatButton').click( function() {
$.post( '{{action("StatController#store")}}', $('form#new_stat').serialize(), function(data) {
$('#statList').load('/take-stats/{{$game->id}}');
},
'json' // I expect a JSON response
);
clearStat();
});
</script>
<script src="{{ URL::asset('js/takeStats/genJavascript.js') }}"></script>
<script src="{{ URL::asset('js/takeStats/videoJS.js') }}"></script>
<script src="{{ URL::asset('js/takeStats/dataJS.js') }}"></script>
</body>
</html>
Here is the controller method:
public function loadStatList($id) {
$userType = Auth::user()->user_type;
if(Auth::check() && Game::where('id', '=', $id)->exists() && ($userType == 'statistician' || $userType == 'admin')) {
$game = Game::find($id);
$players = $game->team->users->where('user_type', 'player');
$stats = Stat::orderBy('video_timestamp', 'desc')->where('game_id', $game->id)->get();
$statMeta = Stat_Meta::all()->where('type', 'recorded');
return view('partials.statList', compact('game', 'players', 'stats', 'statMeta'));
} else {
abort(404);
}
}
I might be missing something but I thought this would do what I am trying to achieve.
I figured it out!Thank #Get Off My Lawn for giving me a bit of a hint that I couldn't just use the #include. I went ahead and figured out how to pre-render the HTML and then bring it in. It is actually not that hard. The idea here is to use a JQuery function to do an AJAX POST upon hitting submit, then use .done to get then new full webpage. After you have that (you can console.log it to see what you're working with at that point, it will be the entire webpage) you can just get the specific div you want to refresh from the .get you performed, and stick it in the same div. Here is the code:
HTML/#include:
<div id="statList">
#include('partials.statList')
</div>
The AJAX/JQuery:
$('input#addStatButton').click( function() {
$.ajax({
type: 'POST',
url: '{{action("StatController#store")}}',
data: $('form#new_stat').serialize(),
})
.done(function(refresh) {
clearStat();
$.get('{{action("StatController#show", [$game->id])}}', function(data) {
var newData = $("#statList" , data)
$( "#statList" ).html( newData );
//console.log(newData);
});
});
});
I'M SO HAPPY Y'ALL!!!
As discussed this is not an answer on your question but a simple explanation you asked in the comments. And it can help somebody else
Laravel and JQuery
How powerfull :-)
First i will try to fit this as much as possible to your needs with the information your provided.
Secondly jquery contains some cool ass functions a lot of people don't know about.
As you described you have a single page website or something like that. That means you have 1 route to show the single page i suggest /take-stats/{{$game->id}}.
In your controller and i use as example the GameController you have something like the following.
class GameController
{
public function __construct()
{
}
//the single page view
public function index()
{
//your singlepage logic here....
return view('games.index'); //something like this?
}
public function create() //this is where you post to
{
//logic to store the game stats...
//this is where you return a succes message or something.
//lets return the index instead :-)
//dont't return $this->index! use redirect to the route.
return redirect()->route('the.route.to.your.index');
}
}
As you see above, we return the single page in the post response. SSo when you post to the store method, and it succeeds it returns the index page.
Now the jquery.
$('input#addStatButton').on( function() {
//this is where to do the post.
$.post(`{{ route('to.your.store.route') }}`, $('form#new_stat').serialize(), (response) => {
//clear the stats because the post is succeeded in here
//also reload the content. The response contains the new html content
//now what we can do is replace the whole content....
//something like $(`html`).html('response);
//or we get the content we need from the response and this is where jquery comes in handy. The response is simply a html response so jquery can create a new dom from it.
let statsList = $(response).find(`#statslist`).html(); //create a dom element of the response.
$(`#statslist`).html(statslist); //put the filtered html in the current list.
//thats all :-)
}).fail(() => {
// a fail save. When the post fails it will come in here.
}).always(() => {
clearStats();
//this is called always even when it fails. You can clear the stats or something in here.
});
});
A short description :
Onclick post button, post to post.route
Controller method does logic and returns as success the index url.
jquery parses the html response and replaces the original content.
done.
I hope this helps you or somebody else. When using a structure like above this code is simply cleaner and faster for it only executes one request.
I'm building an app with ES5 JS just for practice and "fun" where I store websites in localStorage then print them out on the page, i.e. a bookmarker application.
I'm getting a
TypeError: Cannot set property 'innerHTML' of null
error in the console when I run the following code:
index.html
<body onload="fetchBookmarks()">
<div class="container">
...some code
</div>
<div class="jumbotron">
<h2>Bookmark Your Favorite Sites</h2>
<form id="myForm">
...some code
</form>
</div>
<div class="row marketing">
<div class="col-lg-12">
<div id="bookmarksResults"></div> /* problem code */
</div>
</div>
<footer class="footer">
<p>© 2018 Bookmarker</p>
</footer>
</div>
<link rel="stylesheet" href="main.css">
<script src="./index.js"></script>
</body>
index.js
...someJScode that stores the websites in localStorage
function fetchBookmarks() {
var bookmarks = JSON.parse(localStorage.getItem('bookmarks'));
//Get output id
var bookmarksResults = document.getElementById('#bookmarksResults');
bookmarksResults.innerHTML = '';
for(var i = 0; i < bookmarks.length; i++) {
var name = bookmarks[i].name;
var url = bookmarks[i].url;
bookmarksResults.innerHTML += name;
}
}
now, the error is obviously because I am loading the <body> before the <div id="bookmarksResults"></div> so innerHTML responds with null
But two things here:
1) When I assign onload="fetchBookmarks()" to the <footer> element, the function doesn't run.
2) The tututorial I am following has this code almost exactly and it runs there.
I've also tried running the fetchBookmarks() function like this:
window.onload = function() {
fetchBookmarks();
function fetchBookmarks(){
...some JS code
};
}
But that returned the same
TypeError: Cannot set property 'innerHTML' of null
So I'm a bit lost here and am much more interested in figuring out why this isn't working and the theory behind it so I understand JS better (the whole point of building this app in the first place).
Any help would be appreciated! Thanks SO team.
The problem is with this line:
document.getElementById('#bookmarksResults')
You don't need to prefix the ID with # when you're using it with document.getElementById. Either you may remove the # from the method call, or use document.querySelector(), which works the same way, but support CSS-like selectors to select elements from DOM.
document.getElementById('bookmarksResults');
// OR
document.querySelector('#bookmarksResults');
You need to pass the value of the id without the #
Update from
var bookmarksResults = document.getElementById('#bookmarksResults');
to
var bookmarksResults = document.getElementById('bookmarksResults');
I'm trying to use the code of this example (cropper example) of images cropper application in an AngularJS view, but it didn't work. I think the problem is in the elements selection.
This is what I'm doing:
Main application HTML
<div class="view-container layer">
<div class="container content" ng-view>
<!-- load the content of the view--!>
</div>
</div>
The view
It is the code in the body section of the example (view). I omit the whole code; I'm just including the main parts.
<div class="container" id="crop-avatar">
<!-- the div content --!>
</div>
The JavaScript selectors
function CropAvatar($element) {
this.$container = $element;
this.$avatarView = this.$container.find('.avatar-view');
this.$avatar = this.$avatarView.find('img');
this.$avatarModal = this.$container.find('#avatar-modal');
this.$loading = this.$container.find('.loading');
this.$avatarForm = this.$avatarModal.find('.avatar-form');
this.$avatarUpload = this.$avatarForm.find('.avatar-upload');
this.$avatarSrc = this.$avatarForm.find('.avatar-src');
this.$avatarData = this.$avatarForm.find('.avatar-data');
this.$avatarInput = this.$avatarForm.find('.avatar-input');
this.$avatarSave = this.$avatarForm.find('.avatar-save');
this.$avatarBtns = this.$avatarForm.find('.avatar-btns');
this.$avatarWrapper = this.$avatarModal.find('.avatar-wrapper');
this.$avatarPreview = this.$avatarModal.find('.avatar-preview');
this.init();
}
And CropAvatar is initialized as:
$(function () {
return new CropAvatar($('#crop-avatar'));
});
If I used the code in this form, it didn't work at all, but if I put all the HTML code into the <body></body> tags of mi app.html it works fine. It's for this reason that I think it is a selectors problems.
I am trying to read a file in the same directory of an HTML and JavaScript file however it seems to be returning null. Below I have added the code I have from each file.
HTML File:
<html>
<!-- Code to call the Google Maps API and link style.css sheet -->
<body>
<div class="content">
<div id="googleMap"></div>
<div id="right_pane_results">hi</div>
<div id="bottom_pane_options">
<button onclick="get_parameters()">Try It</button>
</div>
</div>
</body>
<script type="text/javascript" src="./javascript.js">
</script>
</html>
JavaScript File:
function get_parameters() {
alert("hi"); // Just to let me know the function is getting called
var freader = new FileReader();
var text;
freader.onload = function(e) {
text = freader.result;
}
freader.readAsText('./test.txt', "ISO-8859-1");
text = freader.result; // To my knowledge, this should be taking the current line freader is on and storing it into text
var div = document.getElementById('bottom_pane_options');
div.innerHTML = div.innerHTML + text;
}
test.txt
Iron
Aluminum
Steel
//etc. for x number of times (depends on data I have parsed previously)
All I would like is for JavaScript to read test.txt and parse it into an array (text). The issue is, when I click the button 'Try It', the alert pops up (telling me the function is being called) and text contains null. I am running all files off my computer and all are in the exact same directory.
I have the Comments handle in my Google App Engine app to display the comments. I want to stop the page from loading if the user (defined as "chooser" here) is not in localStorage.
I get the first 2 alerts: "load event" and chooser: "undefined". Since "chooser" is undefined I expect the else clause to trigger but I don't get the alert in else clause.
Also, the first item in ordered list is displayed but not the rest. So I assume there is an issue with loading of the page. How can I fix this?
class Comments(webapp.RequestHandler):
def get(self):
self.response.out.write("""
<html>
<head>
<title>Choices</title>
<script type="text/javascript">
function showChoices ()
{
alert("load event");
var chooser = localStorage.getItem("chooser");
alert("chooser: " + chooser);
if (chooser)
{
document.getElementById("topten").style.display="inline";
}
else
{
alert("else triggers");
document.write("get an invitation");
}
}
window.onload = showChoices;
</script>
</head>
<body>
<div class="content">""")
#python code:
query = Users.all()
e = query.fetch(10)
self.response.out.write("""<ol>""")
for item in e:
self.response.out.write("""
<div id="topten" class="title" style="display:none">
<li>%s (<span class="small">%s</span>)</li>
</div>
<hr><br />"""
% tuple([item.choice, item.owner]))
self.response.out.write("""</ol>""")
self.response.out.write("""
</div>
</body>
</html>""")
Are you sure that chooser is undefined and not the string literal "undefined"?
see this fiddle i made