JavaScript function call on JQuery .load() doesn't behave like expected - javascript

I am working on a website for school, and am currently implement some sort of admin dashboard. For that, I decided to dynamically load 'modules' (actually simply .php files) into a div designed to hold them.
This works fine for modules that don't depend on specific js files, but there's one that needs the 'participation.js' file.
I had tested the module in a whole window where there was an 'onload="initSelectable()"' on the body directive, but calling this function when the module is loaded in the admin dashboard doesn't do anything.
Here is the content of participation.js (it is simply copy/pasted from the JQuery selectable, and I slightly modified the behaviour):
var selectedPlayerIDs = [];
function initSelectable(){
$('#selectable').selectable();
$('#submitParticipationBtn').hide();
console.log("initSelectable");
$("#selectable").selectable({
stop: function() {
var count = 8;
var result = $("#selectedPlayersCount").empty();
$(".ui-selected", this).each(function() {
count--;
selectedPlayerIDs.push($(this).attr("data-playerid"));
});
if(count > 1)
$('#selectedPlayersCount').html(count + " more players");
else if(count === 1)
$('#selectedPlayersCount').html(count + " more player");
else if(count === 0)
$('#selectedPlayersCount').html("no more player. You're good to go !");
else if(count === -1)
$('#selectedPlayersCount').html(-count + " player less");
else
$('#selectedPlayersCount').html(-count + " players less");
if(count === 0)
$('#submitParticipationBtn').show();
else
$('#submitParticipationBtn').hide();
}
});
}
function submitParticipation(){
alert( "JS loaded" );
$.post("participation.php", {selectedIDs : JSON.stringify(selectedPlayerIDs)}, function() {
})
.onSuccess(function() {
alert( "onSuccess" );
})
.fail(function() {
alert( "error" );
});
}
So basically this code initializes the JQuery Selectable environment. When loading the module in the div, I use $('#dynamicPage').hide().load("module1.php").fadeIn('500'); directly followed by $.getScript("participation.js");
The thing is, the module correctly loads (at least the HTML part), and I can see in the console log ("initSelectable"). But I need to manually re-execute initSelectable() from the command for it to be effective. And when I do that, I see there's an undefined getting logged in the console, before the second ("initSelectable") log (this might be due to the fact that I'm trying to call $('#selectable').selectable(); a second time).
For example, here is the participation module .php file:
<div class="well">
<h3>Create a participation</h3>
<h4>Please select <span id="selectedPlayersCount">8 players</span></h4>
<div class="row">
<div class="col-sm-4">
<ol id="selectable">
<?php include_once "../Ctrl/rankingList.php" ?>
</ol>
<button class="btn btn-success" id="submitParticipationBtn" onclick="submitParticipation()">Submit</button>
</div>
</div>
</div>
I've tried countless different way to call the initSelectable function (callbacks, events, timeOuts, etc...) and no matter what, even if it gets executed by the browser, I still need to manually re-execute it for it to be working...
So basically, my question is:
What is the correct way to load HTML and dependant JS files into a div ?

What is the correct way to load HTML and dependant JS files into a div ?
So, this would be a good start and you can take it from here.
$(function() {
$("#myDiv").load("myfile.php", function() {
console.log("HTML has been injected!");
//Get dependencies
$.getScript( "myscript.js" )
.done(function( script, textStatus ) {
//Call methods from within myscript.js
initSelectable();
})
.fail(function( jqxhr, settings, exception ) {
console.log("There was an error!");
});
});
// Remove inline event handler and bind it like below.
$("#myDiv").on("click", "#submitParticipationBtn", submitParticipation);
function submitParticipation() {
//...
//...
}
});
I am not sure why $('#selectable').selectable() is being duplicated. But, it's left you to fix :)

Okay so I was doing it wrong. I thought that putting the <script src "path/to/script.js"></script> in the module file didn't work. But actually, it does, and I simply needed to call $(document).ready(initSelectable()) in the JS file to be sure the initSelectable was executed at the right time.
So now my .php file looks like this:
<div class="well">
<h3>Create a participation</h3>
<h4>Please select <span id="selectedPlayersCount">8 players</span></h4>
<div class="row">
<div class="col-sm-4">
<ol id="selectable">
<?php include_once "../Ctrl/rankingList.php" ?>
</ol>
<button class="btn btn-success" id="submitParticipationBtn" onclick="submitParticipation()">Submit</button>
</div>
</div>
<script src="../Ctrl/participation.js"></script>
</div>
Thanks all for your help :P

Related

copying Javascript working on a laravel view to another site not working

So on similar sites with different themes, same core functions for laravel there is a view that has
<div class="footer__item footer__item--right"> <div class="footer__item-search"> <span class="search-wrap"><input type="text" placeholder="Search" class="search"></span> </div>
in scripts the only relative javascript code which is also already on the other site
$(document).on('keyup', '.search', function() {
var query = $(this).val().toLowerCase();
doSearch(query);
});
function OnSearch(input) {
var query = input.value.toLowerCase();
doSearch(query);
}
function doSearch(query){
$.getJSON('{{ route('frontend.game.search') }}?category1={{ $category1 }}&q=' + query, function(data) {
$('#games').html(data.data);
});
}```
so copying those makes a box appear but searches nothing
What possibly the javascript is missing to actually be called and call the laravel template view mentioned ?

Knockout.js HTML template not responding to edits?

I don't even know how to describe this, it's so utterly confusing I have no clue where to begin.
I have a Knockout template stored in a <script type="text/html"> tag in my document. I want to edit this template. So I edit it and save it. I notice via the Web Development Tools that the change has taken place by inspecting the script tag and its value.
When Knockout.js applies the template to the DOM, the template has not been changed. In fact, I can entirely remove the template and Knockout magically places the old version of the template in there - as if it's caching it somehow.
I have tried Firefox and Google Chrome, both with cache resets.
For what it's worth, I am also using Require.js, however, I am unsure how this would affect anything as the templates I am trying to use with Knockout are embedded inline in the page, not loaded as an external file.
I suspect that either Knockout.js or Require.js is causing this, but I cannot figure out how.
Template in question (in create.blade.php):
<!-- Any edits or changes made to the following template will not be reflected when Knockout.js uses it, instead it appears to be 'caching' an old version of this template -->
<script type="text/html" id="image-file-template">
<div data-bind="attr: { 'data-index': $index }, visible: $root.visibleTemplate() == ko.unwrap($index)">
<h2 data-bind="text: original_name"></h2>
<form>
<ul class="container">
<li class="grid-4">
<label>
<p>Title</p>
<input type="text" name="title" data-bind="value: title" />
</label>
</li>
<!-- Snip -->
</ul>
</form>
</div>
</script>
Loading of my Knockout ViewModel in the DOM (create.blade.php)
<script data-main="/src/js/common" src="/src/js/require.js"></script>
<script>
require(['common'], function() {
require(['knockout', 'viewmodels/UploadViewModel'], function(ko, UploadViewModel) {
ko.applyBindings(new UploadViewModel());
});
});
</script>
How knockout selects my template on the ViewModel (UploadViewModel.js)
// Declare which template to use when a file is uploaded
self.templateObjectType = function (uploadedFile) {
var uploadedFileType = uploadedFile.type();
if (uploadedFileType == 1) {
return 'image-file-template'; // This is being called, I can confirm via the debugger, but the template being returned appears cached?
} else if (uploadedFileType == 2) {
return 'gif-file-template';
} else if (uploadedFileType == 3) {
return 'audio-file-template';
} else if (uploadedFileType == 4) {
return 'video-file-template';
} else if (uploadedFileType == 5) {
return 'document-file-template';
}
};
My Require.js config (common.js)
requirejs.config({
urlArgs: "bust=" + (new Date()).getTime(),
baseUrl: '/src/js',
paths: {
'text': 'lib/requirejs-text',
'jquery': 'lib/jquery-1.9.1',
'jquery.ui' : 'lib/jquery-ui.min',
"jquery.fracs": 'lib/jquery.fracs-0.15.0',
'dropzone': 'lib/dropzone',
"jquery.throttle-debounce": 'lib/jquery.ba-throttle-debounce.min',
'knockout': 'lib/knockout-3.2.0.debug',
'ko.mapping': 'lib/knockout.mapping-latest',
'ko.postbox': 'lib/knockout-postbox',
'd3': 'lib/d3',
'moment': 'lib/moment',
'sticky': 'lib/sticky'
},
shim: {
"jquery.fracs": ["jquery"],
"jquery.throttle-debounce": ["jquery"]
}
});
Has anyone ever encountered anything remotely like this?

Html.TextBoxFor not rendering when added by a library

I'm currently working on a website at work. Everything's been working so far, except when I've moved a function to a library so it can be reusable.
The function is a click event for a set of two radio buttons. When the "Yes" button is clicked, a textbox and it's label need to appear. When the "No" button is clicked, they need to disappear.
The label is appearing just fine on the "Yes" click. And the function as a whole worked perfectly on the page itself. However, when I moved the script to a library for reusability within the project, the textbox no longer appears. I have tried swapping out for an input tag, with similar results.
The relevant html:
#ModelType PROJECT.Form
#Code
ViewData("Title") = "PageTitle"
Layout = "~/Views/Shared/_LayoutPage.Desktop.vbhtml"
End Code
<script>
$(function () { initFunction() })
</script>
#Using Html.BeginForm("Process", "Home")
#Html.AntiForgeryToken()
#Html.Hidden("page", 4)
#<div id="formColumn" class="grid_19 alpha">
<h3>Process Title</h3>
<fieldset>
<legend>Page Title</legend>
<ol class="grid_18 push_1">
//a couple yes/no questions here, works fine
<li><label>Question 3</label></li>
<li>
<ol id="appendHere"class="horizontalList clearfix">
<li><label>Yes</label></li>
<li>#Html.RadioButtonFor(Function(a) a.Q3Radio, True)</li>
<li><label>No</label></li>
<li>#Html.RadioButtonFor(Function(a) a.Q3Radio, False)</li>
</ol>
</li>
//more working stuff
</ol>
<div class="clear"></div>
<button name="submit" id="submit" value="submit" class="push_1">Submit</button>
<button name="cancel" id="cancel" value="cancel" class="push_1">Cancel</button>
<button name="back" id="back" value="back" class="push_1">Back</button>
</fieldset>
</div>
End Using
The javascript:
function initFunction() {
$(function () { $("input[name=Q3Radio]").click(function () { handleQ3Check(this) }) })
var check = true
function handleQ3Check(elem) {
if (elem.value == "True") {
if (check) {
$('#appendHere').append('<li class="appended"><label>Amount: $</label></li><li class="appended">#Html.TextBoxFor(Function(a) a.appendAmount)</li>')
$(function () { $("input[name=appendAmount]").blur(function () { handleFees(this, 'stuff') }) })
check = false
}
} else {
var appendedInput = $('.appended')
if (appendedInput != null) {
handleFees(appendedInput, 'stuff')
$(appendedInput).remove()
check = true
}
}
}
}
As stated above, I have tried making the textbox out of an input tag, but that does not appear. What appears with this case is Amount: $ #Html.TextboxFor(Function(a) a.appendAmount) exactly like that.
Any help or nudges in the right direction while I further attempt to debug the issue would be greatly appreciated.
When you include the Javascript in the same vbhtml file the reason why it works is that the vbhtml file gets compiled before it is then sent out to the client's browser. Have a look at the javascript that is getting rendered either by viewing the source or using developer tools/or similar in your favourite browser.
When you ask javascript to write out
$('#appendHere').append('<li class="appended"><label>Amount: $</label></li>
<li class="appended">#Html.TextBoxFor(Function(a) a.appendAmount)</li>')
It will do just that.
Judging by your comments it seems as though you're already aware of this though :-) and that you're making progress.

Weird issue where after inserting a doc, it exists for an instant, and then deletes itself?

They way I'm testing this is a simple for loop in the template to run through the elements available to the client and display them in a list.
I insert the elements through a text input identified by #query.
When I enter an element, it displays for a brief instant, and a console log that prints out Links.find().fetch() shows that the element exists, and then shortly afterwards, the element is seemingly automagically removed making any successive calls to Links.find().fetch() yield an empty list. Is this a bug within Meteor? Or is it expected behaviour and bad implementation?
UPDATE
Another weird development, I added setTimeout(function(){Links.find().fetch()},3000); to the server side to try and track what was going on. With this line, the inserts work correctly for a while, and then crashes with these errors: http://i.imgur.com/CUYDO67.png
. What is going on?
Below is my template file myapp.html
<head>
<title>myapp</title>
</head>
<body>
{{> search_bar}}
<br>
{{> list_of_links}}
</body>
<template name="search_bar">
<h1>Playlist</h1>
<input id="query" type="text" placeholder="Enter Query Here"/>
</template>
<template name="list_of_links">
<ul id="item-list">
{{#each my_playlist}}
{{> link_item}}
{{/each}}
</ul>
</template>
<template name="link_item">
<li class="link">
<div class="link-title">{{youtube_link}} {{sess}}</div>
</li>
</template>
And here follows myapp.js
//Setting up a collection of urls
Links = new Meteor.Collection("links");
if (Meteor.isClient) {
//"Subscribing" to server's published data
Deps.autorun( function(){
Meteor.subscribe( "links", Meteor.default_connection._lastSessionId);
});
//Nuke database helper function -- debugging
Template.list_of_links.clean = function(collection) {
if(collection) {
// clean items
_.each(collection.find().fetch(), function(item){
collection.remove({_id: item._id});
});
}
}
//Songs from session
Template.list_of_links.my_playlist = function () {
return Links.find();
};
Template.search_bar.events({
//http://stackoverflow.com/a/13945912/765409
'keypress #query' : function (evt,template) {
// template data, if any, is available in 'this'
if (evt.which === 13){
var url = template.find('#query').value;
//Find a nicer way of clearing shit.
$("#query").val('');
Links.insert({sess:Meteor.default_connection._lastSessionId,youtube_link:url});
var cursor = Links.find();
cursor.rewind();
console.log(cursor.fetch());
//Add to database.
}
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
Meteor.publish("links", function( sess ) {
return Links.find({sess: sess}); //each client will only have links with that _lastSessionId
});
//Making sure permissions are correct
Links.allow({
insert: function (userId, doc) {
return true;
}
});
});
}
That kind of behavior is expected when user doesn't have enough privileges to create a document. The insert function creates a local copy of the doc instantly (thanks to latency compensation), and then sync it with the result of server operation. If that operation fails, the temporary document is purged from client's Minimongo.
Have you created proper rules with Collection.allow? That's the first place to look for the cause.

I have two divs with the same ng-controller in AngularJS, how can I make them share information?

I have two different div tags in my html code referencing the same controller in AngularJS. What I suspect is that since these divs aren't nested they each have their own instance of the controller, thus the data is different in both.
<div ng-controller="AlertCtrl">
<ul>
<li ng-repeat="alert in alerts">
<div class="span4">{{alert.msg}}</div>
</li>
</ul>
</div>
<div ng-controller="AlertCtrl">
<form ng-submit="addAlert()">
<button type="submit" class="btn">Add Alert</button>
</form>
</div>
I know this could easily be fixed by including the button in the first div but I feel this is a really clean and simple example to convey what I am trying to achieve. If we were to push the button and add another object to our alerts array the change will not be reflected in the first div.
function AlertCtrl($scope) {
$scope.alerts = [{
type: 'error',
msg: 'Oh snap! Change a few things up and try submitting again.'
}, {
type: 'success',
msg: 'Well done! You successfully read this important alert message.'
}];
$scope.addAlert = function() {
$scope.alerts.push({
type: 'sucess',
msg: "Another alert!"
});
};
}
This is a very common question. Seems that the best way is to create a service/value and share between then.
mod.service('yourService', function() {
this.sharedInfo= 'default value';
});
function AlertCtrl($scope, yourService) {
$scope.changeSomething = function() {
yourService.sharedInfo = 'another value from one of the controllers';
}
$scope.getValue = function() {
return yourService.sharedInfo;
}
}
<div ng-controller="AlertCtrl">{{getValue()}}</div>
<div ng-controller="AlertCtrl">{{getValue()}}</div>
If I understand the question correctly, you want to sync two html areas with the same controller, keeping data synced.
since these divs aren't nested they each have their own instance of the controller, thus the data is different in both
This isn't true, if you declare the controllers with the same alias (I'm using more recente angular version):
<div ng-controller="AlertCtrl as instance">
{{instance.someVar}}
</div>
<div ng-controller="AlertCtrl as instance">
{{instance.someVar}} (this will be the same as above)
</div>
However, if you WANT them to be different and comunicate each other, you will have to declare different aliases:
<div ng-controller="AlertCtrl as instance1">
{{instance1.someVar}}
</div>
<div ng-controller="AlertCtrl as instance2">
{{instance2.someVar}} (this will not necessarily be the same as above)
</div>
Then you can use services or broadcasts to comunicate between them (the second should be avoided, tough).

Categories