In Backbone Collection, delete a model by link on itself - model-view-controller

Im just trying to delete a model from a collection, with a link on itself.
I've attach the event to the "Eliminar button" but it seems Im losing the reference to the model element that contains it... and can't find it.. can you?:
(function ($) {
//Model
Pelicula = Backbone.Model.extend({
name: "nulo",
link: "#",
description:"nulo"
});
//Colection
Peliculas = Backbone.Collection.extend({
initialize: function (models, options) {
this.bind("add", options.view.addPeliculaLi);
this.bind("remove", options.view.delPeliculaLi);
}
});
//View
AppView = Backbone.View.extend({
el: $("body"),
initialize: function () {
this.peliculas = new Peliculas( null, { view: this });
//here I add a couple of models
this.peliculas.add([
{name: "Flying Dutchman", link:"#", description:"xxxxxxxxxxxx"},
{name: "Black Pearl", link: "#", description:"yyyyyyyyyyyyyy"}
])
},
events: {"click #add-movie":"addPelicula", "click .eliminar":"delPelicula"},
addPelicula: function () {
var pelicula_name = $("#movieName").val();
var pelicula_desc = $("#movieDesc").val();
var pelicula_model = new Pelicula({ name: pelicula_name },{ description: pelicula_desc });
this.peliculas.add( pelicula_model );
},
addPeliculaLi: function (model) {
var str= model.get('name').replace(/\s+/g, '');
elId = str.toLowerCase();
$("#movies-list").append("<li id="+ elId +"> " + model.get('name') + " <a class='eliminar' href='#'>Eliminar</a> </li>");
},
delPelicula: function (model) {
this.peliculas.remove();
console.log("now should be triggered the -delPeliculaLi- event bind in the collection")
},
delPeliculaLi: function (model) {
console.log(model.get('name'));
$("#movies-list").remove(elId);
}
});
var appview = new AppView;
})(jQuery);
And my html is:
<div id="addMovie">
<input id="movieName" type="text" value="Movie Name">
<input id="movieDesc" type="text" value="Movie Description">
<button id="add-movie">Add Movie</button>
</div>
<div id="lasMovies">
<ul id="movies-list"></ul>
</div>

There are several things in this code that won't work. Your major problem here is that you don't tell your collection which model to remove. So in your html you have to assign so unique id that later will identify your model.
// set cid as el id its unique in your collection and automatically generated by collection
addPeliculaLi: function (model) {
$("#movies-list").append("<li id="+ model.cid +"> <a href="+ model.get('link')+">" +
model.get('name') + "</a> <a class='eliminar' href='#'>Eliminar</a> </li>"
);
},
// fetch and delete the model by cid, the callback contains the jQuery delete event
delPelicula: function (event) {
var modelId = this.$(event.currentTarget).attr('id');
var model = this.peliculas.getByCid(modelId);
this.peliculas.remove(model);
// now the remove event should fire
},
// remove the li el fetched by id
delPeliculaLi: function (model) {
this.$('#' + model.cid).remove();
}
If there aren't other errors that I have overlooked your code should work now. This is just a quick fix. Maybe you should have a look at the todos example of Backbone to get some patterns how to structure your app.
http://documentcloud.github.com/backbone/examples/todos/index.html

Related

my code does not safe different pages in my db

js:
$('#sortable').sortable({
stop: function(event, ui) {
saveContentOrder();
}
});
function saveContentOrder()
{
const idsInOrder = $("#sortable").sortable("toArray");
var data = {
idsInOrder:idsInOrder
};
$.ajax({
type: "POST",
url: "/xxx/yyy/zzz",
data: data
}).done( function() {
}).fail(function() {
});
}
index.blade.php:
<tbody id="sortable" >
#foreach ($references as $index => $reference)
<tr id="reference_id_{{$reference->id}}">
<td width="65%">
<a href="{{ route('admin.reference.edit', $reference->id ) }}"><b>{{ $reference->title }}</b>
</a><br>
</td>
<td>
#if(!count($reference->images))<span style="color:#ff0000;font-weight:700;">0</span>#else{{ count($reference->images) }}#endif
</td>
<td>
{{ $reference->priority }}
my webroute:
Route::post('/xxx/yyy/zzz', 'AdminReferenceController#reorder');
my Controller:
public function reorder(Request $request)
{
$order = $request->get('idsInOrder',[]);
if (is_array($order))
{
foreach($order as $position => $idName)
{
$id = str_replace("reference_id_","",$idName);
$gesamt = Reference::all()->count();
$c = \App\Reference::find($id);
if($c)
{
$c->priority = $gesamt-$position;
$c->save();
}
}
}
when i am on my first page it saves the position and priority change that i drag and drop.but when i go to the second page for example and drag and drop the order it gives the same priority as in page 1. which means it displays thinks first that should be 20th or 30th. i basically want it to be on the right order all the time. i have a show 10, show 30, and show 100. when i for example get to the show 30 and i have no pages since i dont have so many entries right now it works without issues. but as soon as i go to show 10 and got 3 pages the priority gets mixed up. how can i fix this
this is js File:
$('#sortable').sortable({
update: function(event, ui) {
saveContentOrder();
}
});
function saveContentOrder()
{
const idsInOrder = $(this).sortable("serialize");
var data = {
idsInOrder:idsInOrder
};
$.ajax({
type: "POST",
url: "/xxx/yyy/zzz",
data: data
}).done( function() {
}).fail(function() {
});
}
this is controller file
public function reorder(Request $oRequest)
{
//$oRequest->idsInOrder get all orders positiion ids.affter drag
data like,
//orders[]=6&orders[]=5&orders[]=3&orders[]=4&orders[]=2&orders[]=1
parse_str($oRequest->idsInOrder);
$nCount = 1;
foreach($orders as $order)
{
// update database order
$nCount++;
}
return Response::json(['success' => true]);
}

Bootstrap Typeahead with AJAX source (not working)

I'm trying to implement a search bar dropdown using bootstrap v3.0.0 with typeahead.js.
My search bar will take a student's firstname and lastname. I'm using a MYSQL database which consists of a table called practice with afirstname, alastname, aid as columns. The search bar should not only contain the firstname and lastname in the dropdown, but also the id associated with it in a second row. I've read all the examples on the typeahead.js page and I'm unable to do it with ajax call.
Below is the code of my index.php
JS
<script type="text/javascript">
$(document).ready(function() {
$('.cr.typeahead').typeahead({
source: header: '<h3>Select</h3>',
name: 'accounts',
source: function (query, process) {
return $.getJSON(
'localhost/resultly/source.php',
{ query: query },
function (data) {
return process(data);
});
});
});
</script>
HTML:
<body>
<div class="container">
<br/><br/>
<input type="text" name="query" class="form-control cr typeahead" id="firstname" />
<br/><br/>
</div>
</body>
Code for source.php : This should return the firstname and lastname from my database in the form of a json string or object?
<?php
$query = $_POST['query'];
try {
$conn = new PDO('mysql:host=localhost;dbname=practice','root','');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare("SELECT * FROM actualtable WHERE afirstname LIKE '%($query)%'");
$stmt->execute();
}
catch (PDOException $e) {
echo 'ERROR:' . $e->getMessage();
}
foreach ($stmt as $row) {
$afirstname[] = $row['afirstname'];
$alastname[] = $row['alastname'];
}
echo json_encode($afirstname);
echo json_encode($alastname);
?>
result:
http://oi41.tinypic.com/50moi1.jpg
Nothing shows up. I've tried adding a prefetch:
prefetch: {
url: 'localhost/resultly/source.php',
filter: function(data) {
r1 = [];
for (var i = 0; i < data.length; i++) {
r1.push({
value: data[i].afirstname,
tokens: [data[i].afirstname, data[i]alastname],
afirstname: data[i].afirstname,
alastname: data[i].alastname,
template: '<p>{{afirstname}} - {{alastname}}</p>',
});
}
return r1;
}
}
Please do provide a solution or an example which I could refer.
Update:
The source.php should return a list of json encoded data. I debugged by looking at the output that the source.pho created. What I did wrong was whenever I was supposed to put a url I did localhost/source.php instead of just source.php.
Solution provided by Bass Jobsen works and now I have run into another problem.
I'm using
if(isset($_POST['query']))
{ $q_uery = $_POST['query'];
$query = ucfirst(strtolower($q_uery))};
to take the user's data and use it for searching logic
$stmt = $conn->prepare("SELECT * FROM actualtable WHERE afirstname LIKE '%($query)%'");
The updated source.php is http://pastebin.com/T9Q4m10g
I get an error on this line saying Notice: Undefined variable: stmt I guess the $query is not being initialized. How do I get this to work. Thanks.
Update 3
I used prefetch: instead of 'remote:' that did all the matching.
Your return is not correct:
echo json_encode($afirstname);
echo json_encode($alastname);
See for example Twitter TypeAhead.js not updating input
Try echo json_encode((object)$stmt);, see: typeahead.js search from beginng
Update
I tried echo json_encode((object)$stmt);still doesn't work.
Do you use any kind of debugging? What does? source.php return? Try to follow the steps from
typeahead.js search from beginng without the filter.
html:
<div class="demo">
<input class="typeahead" value="" type="text" spellcheck="off" autocomplete="off" placeholder="countries">
</div>
javascript:
$('.typeahead').typeahead({
remote: 'http://testdrive/source.php?q=%QUERY',
limit: 10
});
php (source.php):
<?php
$people = array();
$people[] = array("lastname"=>"Inaw",
"firstname"=>"Dsajhjkdsa");
$people[] = array("lastname"=>"Dsahjk",
"firstname"=>"YYYsgbm");
$people[] = array("lastname"=>"Dasjhdsjka",
"firstname"=>"JHJKGJ");
$datums = array();
foreach($people as $human)
{
$datums[]=(object)array('value'=>$human['firstname'],'tokens'=>array($human['firstname'],$human['lastname']));
}
echo json_encode((object)$datums);
This should work
update2
Thanks, it worked. How do I display 2 or more 'value'?
add some values to your datums in source.php:
foreach($people as $human)
{
$datums[]=(object)array
(
'value'=>$human['firstname'],
'tokens'=>array($human['firstname'],$human['lastname']),
'firstname'=>$human['firstname'],
'lastname'=>$human['lastname']
);
}
firstname and lastname now are field you csn use in your templates
Add a template and template engine to your javascript declaration:
$('.typeahead').typeahead({
remote: 'http://testdrive/source.php?q=%QUERY',
limit: 10,
template: [
'<p>{{firstname}} - {{lastname}}</p>'
].join(''),
engine: Hogan
});
The above make use of https://github.com/twitter/hogan.js. You will have to include the template engine by javascript, for example:
<script src="http://twitter.github.io/typeahead.js/js/hogan-2.0.0.js"></script>
It is working for me. please follow below step.
Please add below Js and give proper reference.
bootstrap3-typeahead
--- Ajax Call ----
$("#cityId").keyup(function () {
var al = $(this).val();
$('#cityId').typeahead({
source: function (valuequery, process) {
var states = [];
return $.ajax({
url: http://localhost:4000/GetcityList,
type: 'POST',
data: { valueType: "", valueFilter: valuequery },
dataType: 'JSON',
success: function (result) {
var resultList = result.map(function (item) {
states.push({
"name": item.Value,
"value": item.Key
});
});
return process(states);
}
});
},
});
});
---- Cs Code ---
public JsonResult SearchKeyValuesByValue(string valueType, string valueFilter)
{
List<KeyValueType> returnValue = SearchKeyValuesByValue(valueType, valueFilter);
return Json(returnValue);
}
Auto suggest of Bootstrap typehead will get accept only "name" and "value" so create reponse accordinly

Marionette controller.listenTo not capturing event

I'm having a weird problem with some Backbone Marionette controller in a sub-application module.
I cannot make it to work capturing one of its view events with the "controller.listenTo(view, 'event', ...)" method, although the "view.on('event',...)" works no problem.
Here is the sample code for the module views :
MyApp.module("SubApp.Selector", function (Selector, App, Backbone, Marionette, $, _) {
"use strict";
// Category Selector View
// ------------------
// Display a list of categories in the selector
// Categories list item
Selector.CategoryOption = Marionette.ItemView.extend({
template: "#my-category-template",
tagName: "option",
onRender: function () { this.$el.attr('value', this.model.get('id')); }
});
// Categories list container
Selector.CategoryListView = Marionette.CompositeView.extend({
template: "#my-category-list-template",
tagName: "div",
id: "categories",
itemView: Selector.CategoryOption,
itemViewContainer: "select",
events: {
'change #category_items': 'categoryClicked'
},
categoryClicked: function() {
var catID = this.$('#category_items').val();
console.log("category clicked "+catID);
this.trigger("category:changed", catID);
}
});
// Selector Component Controller
// -------------------------------
Selector.Viewer = Marionette.Controller.extend({
initialize: function (_options) {
this.region = _options.region;
this.collection = _options.collection;
},
show: function () {
var view = new Selector.CategoryListView({ collection: this.collection });
this.listenTo(view, 'category:changed', this.categoryChanged);
//view.on('category:changed', this.categoryChanged, this);
this.region.show(view);
},
categoryChanged: function (_category) {
console.log("category changed in controller");
}
});
});
Is there anything I got wrong about event listening from a controller object ?
Shouldn't I use the listenTo syntax as is seems to be recommended widely for proper event handling and listener destruction ?

AngularJS update View after Model loaded from Ajax

I'm newbie of angularjs developing and i wrote this simple app, but don't understand how i can update view, after the model il loaded from ajax request on startup!
This code don't work when I add delay into photos.php, using:
sleep(3);
for simulate remote server delay! instead if search.php is speedy it work!!
<!doctype html>
<html ng-app="photoApp">
<head>
<title>Photo Gallery</title>
</head>
<body>
<div ng-view></div>
<script src="../angular.min.js"></script>
<script>
'use strict';
var photos = []; //model
var photoAppModule = angular.module('photoApp', []);
photoAppModule.config(function($routeProvider) {
$routeProvider.when('/photos', {
templateUrl: 'photo-list.html',
controller: 'listCtrl' });
$routeProvider.otherwise({redirectTo: '/photos'});
})
.run(function($http) {
$http.get('photos.php')//load model with delay
.success(function(json) {
photos = json; ///THE PROBLEM HERE!! if photos.php is slow DON'T update the view!
});
})
.controller('listCtrl', function($scope) {
$scope.photos = photos;
});
</script>
</body>
</html>
output of photos.php
[{"file": "cat.jpg", "description": "my cat in my house"},
{"file": "house.jpg", "description": "my house"},
{"file": "sky.jpg", "description": "sky over my house"}]
photo-list.html
<ul>
<li ng-repeat="photo in photos ">
<a href="#/photos/{{ $index }}">
<img ng-src="images/thumb/{{photo.file}}" alt="{{photo.description}}" />
</a>
</li>
</ul>
EDIT 1, Defer solution:
.run(function($http, $q) {
var deferred = $q.defer();
$http.get('photos.php')//load model with delay
.success(function(json) {
console.log(json);
photos = json; ///THE PROBLEM!! if photos.php is slow DON'T update the view!
deferred.resolve(json);//THE SOLUTION!
});
photos = deferred.promise;
})
EDIT 2, Service solution:
...
//require angular-resource.min.js
angular.module('photoApp.service', ['ngResource']).factory('photoList', function($resource) {
var Res = $resource('photos.php', {},
{
query: {method:'GET', params:{}, isArray:true}
});
return Res;
});
var photoAppModule = angular.module('photoApp', ['photoApp.service']);
...
.run(function($http, photoList) {
photos = photoList.query();
})
...
The short answer is this:
.controller('listCtrl', ['$scope', '$timeout', function($scope, $timeout) {
$timeout(function () {
$scope.photos = photos;
}, 0);
}]);
The long answer is: Please don't mix regular javascript and angular like this. Re-write your code so that angular knows what's going on at all times.
var photoAppModule = angular.module('photoApp', []);
photoAppModule.config(function($routeProvider) {
$routeProvider.when('/photos', {
templateUrl: 'photo-list.html',
controller: 'listCtrl'
});
$routeProvider.otherwise({redirectTo: '/photos'});
});
photoAppModule.controller('listCtrl', ['$scope', function($scope) {
$scope.photos = {};
$http.get('photos.php') // load model with delay
.success(function(json) {
$scope.photos = json; // No more problems
});
}]);
use broadcast
//service
var mydata = [];
this.update = function(){
$http.get(url).success(function(data){
mydata = data;
broadcastMe();
});
};
this.broadcastMe = function(){
$rootScope.$broadcast('mybroadcast');
};
//controller
$scope.$on('mybroadcast', function(){
$scope.mydata = service.mydata;
};
http://bresleveloper.blogspot.co.il/
EDIT:couple of days ago i've learned the best practice
http://bresleveloper.blogspot.co.il/2013/08/breslevelopers-angularjs-tutorial.html
I think you're better off using high level angular services for data transfer, also look into promises and services:
http://docs.angularjs.org/api/ng.$q
You need to bind an element in your view to a property (simple or object) of your $scope object. Once the $scope object is updated the view should be updated on its own. That is the beauty of AngularJS.
EDIT:
Please register your controller as
photoAppModule.controller('listCtrl', function($scope){
$scope.photos = photos;
});
If photos variable is not available, then you might have to create a service with the variable and inject in the controller.

in extjs how to bind store to view which is included as item in other view

i am working in extjs. i have view as-
QbqnsResultmain.js
Ext.define('Balaee.view.qb.qbqns.QbqnsResultmain',
{
extend:'Ext.form.Panel',
requires:[
'Balaee.view.qb.qbqns.QbqnsResult'
],
id:'QbqnsResultmainId',
alias:'widget.QbqnsResultmain',
title:'Result',
height:400,
items:[
{
xtype:'QbqnsResult',
},
],
buttons:[
{
xtype:'button',
fieldLabel:'review',
action:'getreview',
name:'review',
formBind:true,
text:'Review',
},
{
xtype:'button',
fieldLabel:'papers',
action:'getpapers',
name:'papers',
formBind:true,
text:'Get all papers',
},
]});
and QbqnsResult.js-
Ext.define('Balaee.view.qb.qbqns.QbqnsResult',
{
extend:'Ext.view.View',
id:'QbqnsResultId',
alias:'widget.QbqnsResult',
//store:'kp.PollStore',
store:'qb.QbqnsStore',
config:
{
tpl:'<tpl for="1">'+
'<div id="main">'+
'</br>'+
//'<b>Question :-</b></br>'+
'<h1 id="q">Total number of Questions are:-</h1>{TotalQuestions}</br>'+
'<h1 id="q">Number of attempted Questions:-</h1> {Attempted}</br>'+
'<h1 id="q">Number of correct answers:-</h1> {CorrectAnswers}</br>'+
'<h1 id="q">Total score:-</h1> {Total}</br>'+
'<h1 id="q">Score you got is:-</h1> {Score}</br>'+
'<h1 id="q">percentage you got is:-</h1> {percentage}</br>'+
'<p>---------------------------------------------------------</p>'+
'</div>'+
'</tpl>',
itemSelector:'div.main',
}
});
On click of submit button,i want to show above view. So i had written code in controller as-
check:function()
{
var resultStore=Ext.create('Balaee.store.qb.QbqnsStore');
proxy=resultStore.getProxy();
Ext.apply(proxy.api,{
read:'index.php/QuestionBank/qbpaper/getResult',
create:'index.php/QuestionBank/qbpaper/getResult'
});
Ext.apply(proxy.reader,{
type:'json',
//root:'polls',
root:'questions'
});
Ext.apply(proxy.writer,{
type:'json',
//root:'polls',
root:'data'
});
var getdata=this.getLocalvalue();
console.log(getdata.data);
Paperno=getdata.data.questionPaperNo;
UserId=getdata.data.userId;
var answers = '{"data":[';
answers = answers + '{"paperNo":"'+Paperno+'","userId":"'+UserId+'"}';
answers =answers+']}';
console.log(answers);
resultStore.load({
params:{
data: answers
},
callback: function(records,operation,success){
console.log(records);
console.log("Successfully data send");
},
scope:this
});
var temp= Ext.getCmp('qbqnsId');
temp.removeAll();
var worldChaptor3 =temp.add({xtype:'QbqnsResultmain',
id:'QbqnsResultmainId',
store:resultStore});
},
So i want to bind resultStore to QbqnsResult view's tpl which i have included as xtype in QbqnsResultmain view. But resultStore get binded to Qbqnsresultmain view but not to Qbqnsresult which is included as item in it by means of its xtype. So how to bind store to it. Can someone guide me
One way to do it can be:
var worldChaptor3 =temp.add({xtype:'QbqnsResultmain',
id:'QbqnsResultmainId',
store:resultStore});
worldChaptor3.down('QbqnsResultmain > QbqnsResult').bindStore(resultStore);
But, it would be better if you do it in your QbqnsResultmain, i'll do it on the afterrender event, that way, you can bind the store automatically on creation.

Resources