Use getJSON for Data in Ember.js - ruby-on-rails-3

First time using Ember.
I've read everything I can and can use help building my understanding.
I've been able to render the Ember template inside the rails template.
Now I'm working on binding data using getJSON to the ember template, but I'm getting a few errors. Uncaught TypeError: Cannot call method 'reopenClass' of undefined Error while loading route: TypeError {}
api/v1/newslinks_controller.rb
class Api::V1::NewslinksController < ApplicationController
respond_to :json
def index
respond_with Newslink.all
end
def create
respond_with Newslink.create(params[:newslink])
end
def update
respond_with Newslink.update(params[:id], params[:newslink])
end
def destroy
respond_with Newslink.destroy(params[:id])
end
end
/api/v1/newslinks.json
{"newslinks":[{"id":1,"title":"A Sample Post","navlink":"This will be a simple post record."}]}
app.js
App = Ember.Application.create({
LOG_TRANSITIONS: true,
LOG_ACTIVE_GENERATION: true,
LOG_VIEW_LOOKUPS: true,
rootElement: '#ember',
ready: function() {
console.log('I am app');
}
});
App.Router.map(function() {
this.resource('newslinks', { path: '/' });
console.log("I am router")
});
App.IndexRoute = Ember.Route.extend({
});
App.NewslinksRoute = Ember.Route.extend({
model: function() {
return App.Newslink.all();
}
});
App.Newslink.reopenClass({
all: function() {
return $.getJSON("/api/v1.newslinks_controller.json").then(function(response) {
var newslinks = [];
response.newslinks.forEach(function(newslink) {
newslinks.push(App.Newslink.create(newslink));
});
return newslinks;
});
}
});
newslinks.handlebars
<div class="offset1">
<h1>Newslinks</h1>
<ul>
{{#each newslink in model}}
<li>{{newslink.title}}</li>
<li>{{newslink.navlink}}</li>
{{else}}
<li>There is no news.</li>
{{/each}}
</ul>
{{outlet}}
</div>
Grateful for any assistance!

You haven't declared your App.Newslink class.
Use:
App.Newslink = Ember.Object.extend();
before
App.Newslink.reopenClass ...

Related

vuejs dynamically adding class

Using vuejs 3. In the vuejs app, I have:
data(){
return{
return_prohibited:false
}
}
return_prohibited turns to true when the server returns an error message from a fetch request:
fetch(myUrl,this.myInit)
.then(response => response.json())
.then(data => {
if (data.message) {
this.credits = []
this.debits = []
return_prohibited = true
} // cut for brievity
Html file:
<button #click="previousMonth" id="bouton_mois_prec" :class="{interdit:return_prohibited}" >précédent</button>
I was expecting that the css class interdit would be added to the button each time that return_probibited is true, as per these explanations. But nothing happens.
You should append this. in front of return_prohibited - otherwise you will get errors in the console.

Unable to set data fetched with beforeRouteEnter hook - vuesj2

I have an article component:
<template>
<article class="content">
<div class="content__inner">
<h1 v-html="post.title" class="content__title"></h1>
<div :style="{ backgroundImage: 'url(' + post.image + ')' }" class="content__img"></div>
<div class="content__meta">
<h5>by {{post.author}}</h5>
<h5>{{post.date}}</h5>
</div>
<div v-html="post.content" class="content__text"></div>
</div>
<app-share></app-share>
<!--<related :post="{category:post.categories,id:post.id}"></related>-->
</article>
</template>
<script>
import Share from './Share.vue';
import RelatedPosts from './RelatedPosts.vue';
import axios from 'axios';
export default {
name:'article-gy',
components:{
appShare:Share,
related:RelatedPosts
},
data(){
return{
post:{}
}
},
created(){
console.log('inside created',this.post)
//this.$on('changeContent', post => {
//this.post = post
//document.body.scrollTop = document.documentElement.scrollTop = 0;
//this.$router.push('/'+this.post.slug)
//sessionStorage.setItem('currentPost',JSON.stringify(this.post))
//})
},
destroyed(){
//sessionStorage.removeItem('currentPost')
},
beforeRouteEnter(to,from,next){
if(to.params.post){
next(vm=>{
vm.post.id = to.params.post.id
vm.post.content = to.params.post.content.rendered
vm.post.image = to.params.post.better_featured_image.source_url
vm.post.author = to.params.post.post_author
vm.post.date = to.params.post.date
vm.post.title = to.params.post.title.rendered
vm.post.categories = to.params.post.categories
sessionStorage.setItem('currentPost',JSON.stringify(vm.post))
console.log('inside next',vm.post.id)
})
}
else{
axios.get('/posts?slug='+to.path)
.then(response => response.data[0])
.then(post =>{
next(vm =>{
vm.post.content = post.content.rendered
vm.post.author = post.post_author
vm.post.image = post.better_featured_image.source_url
vm.post.date = post.date
vm.post.title = post.title.rendered
vm.post.categories = post.categories
vm.post.id = post.id
sessionStorage.setItem('currentPost',JSON.stringify(vm.post))
console.log('inside next',vm.post.id)
})
})
}
}
}
</script>
in the beforeRouteEnter hook I'm trying to set some data with an if else condition, if the first condition apply, it means that the user come from another page that belong to the website, this page pass some data via the params object.
In the other case I do another request in order to fetch the correct post data related to the slug.
Now seem that the data are fetched but not displayed in the template. In the created hook if I console log the post variable I actually see the data, but I dont know why the post data are not displayed.
The strange thing is: if I do, in the created hook:
console.log(this.post)
I get the data, but if, for instance, I do:
console.log(this.post.id)
I get undefinded.
This not happens inside next, where I get the right data, even if I console log the post.id
How can this is possible?
Thanks
EDIT
I've tried another solution, avoiding the beforeRouteUpdate hook and working only with the created hook:
created(){
//this.$on('changeContent', post => {
//this.post = post
//document.body.scrollTop = document.documentElement.scrollTop = 0;
//this.$router.push('/'+this.post.slug)
//sessionStorage.setItem('currentPost',JSON.stringify(this.post))
//})
if(this.$route.params.post){
this.post.id = this.$route.params.post.id
this.post.content = this.$route.params.post.content.rendered
this.post.image = this.$route.params.post.better_featured_image.source_url
this.post.author = this.$route.params.post.post_author
this.post.date = this.$route.params.post.date
this.post.title = this.$route.params.post.title.rendered
this.post.categories = this.$route.params.post.categories
}else{
//console.log(this.$route.params.slug)//
axios.get('/posts?slug='+this.$route.params.slug)
.then(response => response.data[0])
.then(post=>{
this.post.id = post.id
this.post.content = post.content.rendered
this.post.image = post.better_featured_image.source_url
this.post.author = post.post_author
this.post.date = post.date
this.post.title = post.title.rendered
this.post.categories = post.categories
console.log('inside then',this.post)
})
}
},
but doesnt' works anyway, if the route has the post object into this.$route.params, the content is loaded, else the content is fetched via axios but not displayed

Trying to use datatables in Slim 3 what is the best way/structure to make the ajax call

I am trying to use datatables inside a view in Slim 3. To me the simplest way to use datatables is to make an ajax call, because I don't know how I would pass a json object to datatables from a controller. I'm not sure where to put my ajax calls. Should I create another folder in my App folder and call it ajax? Or am I going about this datatables all wrong?
here is my controller
<?php
namespace App\Controllers\Dashboards;
use App\Controllers\Controller;
class AdminDashboardController extends Controller
{
public function listAction($request, $response)
{
return $this->view->render($response,'dashboards/admin.html.twig');
}
}
here is my view
{% extends 'base.html.twig' %}
{% block body %}
<h1>this will be the admin dash</h1>
{% endblock %}
{% block javascripts %}
{{parent()}}
<script>
$(document).ready(function() {
$.ajax({
url: "../src/App/ajax/getAll.php",
type: "GET",
dataType: 'json',
}).done(function (result) {
console.log(result);
}).fail(function (jqXHR, textStatus, error) {
console.log("getArchivedPo: " + error);
});
});
</script>
{% endblock %}
and here is my ajax
<?php
$conn = $container['db'];
//$conn = $container->get('db');
$admin = array();
if ($conn) {
$sql = "SELECT trannum,
trantype,
tranbatch,
trandate,
username,
trvnum,
tranaccount,
tranamt,
transtatus,
trannumdocs
FROM BD.BDPTV
INNER JOIN BD.BDUSERS
ON BD.BDUSERS.usernumber = BD.BDPTV.tranuser
WHERE transtatus NOT IN ( 3, 7, 5 )";
$stmt = db2_prepare($conn, $sql);
if ($stmt) {
$result = db2_execute($stmt);
if ($result) {
while ($row = db2_fetch_array($stmt)) {
$admin[] = array(
'trnum' => $row[0],
'trtyp' => $row[1],
'trbatch' => $row[2],
'trdate' => $row[3],
'usrnam' => $row[4],
'trvnum' => $row[5],
'tracct' => $row[6],
'tramt' => $row[7],
'trvsts' => $row[8],
'numdoc' => $row[9]
);
}
} else {
error_log(db2_stmt_errormsg($stmt));
}
} else {
error_log(db2_stmt_errormsg($stmt));
}
} else {
error_log(db2_conn_errormsg());
}
$admin['data'] = $admin;
echo json_encode($admin);
Also, righ tnow I'm getting this error <b>Notice</b>: Undefined variable: container in <b>/www/slim/htdocs/bd/src/App/ajax/getAll.php</b> on line <b>3</b><br />
{"data":[]}
So should I put my ajax somewhere else?
my routes
<?php
$app->get('/', 'HomeController:indexAction')->setName('home');
$app->get('/admindash', 'AdminDashboardController:listAction')->setName('admindash');
$app->get('/ajaxrequest', [AdminDashboardController::class, 'ajax'])->setName('myAjaxRequest');
$app->get('/poentry', 'PoController:entryAction')->setName('poentry');
$app->get('/poedit', 'PoController:editAction')->setName('poedit');
$app->get('/poarchive', 'PoController:archiveAction')->setName('poarchive');
$app->get('/voucherwithpo', 'VoucherController:entryWithPoAction')->setName('voucherwithpo');
$app->get('/voucherwithoutpo', 'VoucherController:entryWithOutPoAction')->setName('voucherwithoutpo');
$app->get('/edituser', 'UserController:editAction')->setName('edituser');
$app->get('/adduser', 'UserController:addAction')->setName('adduser');
$app->get('/poarchivedash', 'ArchivePoDashboardController:listAction')->setName('poarchivedash');
$app->get('/voucherarchivedash', 'ArchiveVoucherDashboardController:listAction')->setName('voucherarchivedash');
$app->get('/notedash', 'NoteDashboardController:listAction')->setName('notedash');
Firstly about the error message you get: You need to include parts of the slim start up where you define the container and the $container['db'] otherwise that cannot be found.
But now the solution where you do not have an additional php file:
You should add a route for the ajax request you could do that in the AdminDashboardController as well
class AdminDashboardController {
// listAction function
function ajax($request, $response) {
// copy from your ajax file
return $response->withJson($admin);
}
}
then add a route:
$app->get('/ajaxrequest', 'AdminDashboardController:ajax')->setName('myAjaxRequest');
And then you can reference that route inside your twig file
$(document).ready(function() {
$.ajax({
url: "{{ path_for('myAjaxRequest') }}",
type: "GET",
dataType: 'json',
}).done(function (result) {
console.log(result);
}).fail(function (jqXHR, textStatus, error) {
console.log("getArchivedPo: " + error);
});
});

Vue and data from REST API

While playing around with vue.js I noticed some strange behavior while trying to display on a page data from an API, but here's the strange thing :
using vue 2.0.0, i can see the "Title", but I have an error in dev console [see printscreen]
using the latest vue version, i can't see the "Title" [and I have the same error in the printscreen]
Is it normal, or?
Source code :
template:
'<div>'+
'Form with id = {{id}}'+
'<br/>'+
'has title = {{item.details.Title}}'+
'</div>',
data: function(){
return {
id: '',
item: {}
}
},
created: function() {
this.get()
},
methods: {
get: function() {
var self = this
id = window.location.hash
id = id.replace('#/whatever/','')
axiosInstance.get('/thebackendresource/'+id) // <--- make http calls etc
.then(function (response) {
self.id = id
self.item = response.data
console.log(self.item)
}).catch(function (error) {
console.log(error)
}
);
}
}
You are getting this error, because when you are fetching data from axiosinstance, that time item.details is null, and when it tries to render it throws this error.
Once the api call is completed, it updates the the DOM and in turn re-renders the DOM, so you can see item.details.Title rendered.
You need to add a null check to prevent this error, which can be easily done using v-if, like follwoing:
template:
'<div>'+
'Form with id = {{id}}'+
'<br/>'+
'<span v-if="item.details"> has title = {{item.details.Title}}'+
'</span>' +
'</div>',

updating global variable using Backbone in Rails

I have the save function of my single page application now up and running, with different front end models and collections in Backbone (a song.js and songsCollection.js), saving to the appropriate backend model in Rails (song.rb). After the user creates a song, comprised of beats and measures, etc....., the backbone routes takes the user to the url containing the song, however, the golbal variable that I used to pass in the all of the songs in the begining of the page start is not getting updated.
How can I call from backbone (either in the routes, or the view), a method or something, to refetch all of the songs from the database, including the recently created song, preferably without changing the Rails side of the URL (prior to the #hash)?
The App.songs variable located within the Assets.js.erb is what I am interested in updated from Rails, after a new song is created.....
I am not opposed to using the gon gem, but if I did, how would I call it to be updated?
Thinking aloud:
Maybe in the assests.js.erb I could have this :
App.updateThis = function(appSongs) {
// then an ajax/pjax call to the Rails songs_controller.rb that returns newAllSongs
appSongs = { songs: newAllSongs }
return appSongs; // this would/should update the global variable
}
Files for reference:
application.js:
require([
'MYAPPLICATION' // this gets passed in as 'Application'
], function(Application){
Application.initialize(App.songs);
});
MYAPPLICATION.js:
define([
'jquery',
'underscore',
'backbone',
'backbone/routers/router', // Request router.js
], function($, _, Backbone, Router){
var initialize = function(options){
window.router = Router.initialize(options);
}
return {
initialize: initialize
};
});
This file is used to package the AssetsPipeline paths to the images and sounds, and pass them to the application when it is rendered, form the gist :
https://gist.github.com/patrickberkeley/3879730
assets.js.erb :
App = {};
App.assets = {
// Returns an object containing all of asset pipeline's image paths.
// This hash is because Rails' Asset Pipeline bundles the routes to files
// per user session, then hands that to the user's session browser, for security.
// So we create in Ruby (erb = embedded ruby) a hash of the images to be accessed
// in the JS.
images: {
<% AssetsUtil.images.each do |img| %>
"<%= img %>" : "<%= asset_path(img) %>",
<% end %>
},
// Return a formatted URL for an asset.
path: function(name) {
// If the file is in our images object, pull the path from there.
if (this.images && this.images[name]) {
return this.images[name];
}
// Otherwise, create a generic asset path.
return '/assets/' + name;
}
};
App.songs = {
songs: <%= Song.all.to_json.html_safe %>
};
routes.js (backbone's route, not rails' route)
define([
.... require.js paths .....
], function($, _, Backbone, mainHomeView, beatSliderView, beatBarsView, componentsView, tempoSliderView, transportView, repButtonView, log, songsCollection, songsViewNew, songsViewIndex, songsViewShow, songsViewEdit){
var AppRouter = Backbone.Router.extend({
songs: {},
routes: {
'new' : 'newSong',
'index' : 'index',
':id/edit' : 'edit',
':id' : 'show',
'.*' : 'newSong'
},
newSong: function(){
var view = new songsViewNew({collection : this.songs});
/// A WHOLE BUNCH OF RENDERING....
},
index: function(){
console.log('bb routes index');
},
show: function(id){
var createdSong = this.songs.get(id);
var view = new songsViewShow(createdSong);
},
edit: function(id){
console.log('bb routes edit');
},
});
// Initialize the Router, with the options, where (options) is declared in MYAPPLCIATION.js
// and called from application.js
//
// (options) == 'assest.js.erb' => App.songs{ songs : <%= Song.all.to_json.html_safe %> }
// (options) == All the songs in the DB
var initialize = function(options){
var app_router = new AppRouter;
app_router.songs = new songsCollection();
app_router.songs.reset(options.songs);
name = '';
$('.component').each( function() {
name = name + $(this).attr('id') + '.';
$(this).children('.measure').each( function() {
name = name + $(this).attr('id') + '.';
$(this).children('.beat').each( function() {
name = name + $(this).attr('id') + '.';
});
});
log.sendLog([[1, "Component structure: "+name]]);
name = '';
});
Backbone.history.start();
return app_router;
};
return {
initialize: initialize
};
});
Using:
rails 3.2.2
backbone.js via gem 'rails-backbone'
require.js via gem 'requirejs-rails'
If I understand your question, you simply need to perform a 'fetch' on the collection after a successful update.