I have been trying to save checkbox values as they are checked by the user. No save button for this part is needed.
This is a many-to-many relationship and therefore, it’s the relation table that gets updated with the new values.
The array returned by Livewire to updatedSelected() is the same as initial values from the database and that is where I am stuck.
The problem is when values exist in the DB, load the page, uncheck one or more and the array returned to updatedSelected() is the same as it was initially loaded on page load.
On checking a checkbox the values are updated properly as I get the full array of values as expected.
When unchecking, what I am expecting is only the values that are left checked to properly sync the model.
If you have any clues on this, your help would be appreciated!
pefumes.php
public $selected = [];
protected $rules = [
"selected.*" => "required"
];
public function updatedSelected( $values )
{
$this->validate();
if( $this->plant->id != null )
{
$this->plant->perfumes()->sync(
array_map( "intval", $values )
);
}
}
perfumes.blade.php
<div class="auto-grid-placement auto-grid-item">
#foreach( $perfumes as $perfume )
#php
$slug = slugafy( $perfume->name );
#endphp
<x-form.label for="{{ $slug }}-{{ $perfume->id }}" class="{{ $disabled }} checkbox-item px-2 py-2 inline-block">
<input wire:model="selected" type="checkbox" id="{{ $slug }}-{{ $perfume->id }}" class="" value="{{ $perfume->id }}" {{ $disabled }}> {{ $perfume->name }} - {{ $perfume->id }}
</x-form.label>
#endforeach
</div>
To further express the issue.
I was able to get through this by changing the wire:model="selected" to wire:click=”savePerfumes( $perfume->id)” by calling a method to filter and save the input values. This is the example that got me on the right track: https://www.youtube.com/watch?v=gNuWLHiRn-o
I must then conclude that the approach of calling the wire:model=”selectedPerfume”, the set array, on every checkbox is probably better, if not made for, single-use checkboxes and these are not checked from values from the DB on load, like most examples you see.
If one needs to check and uncheck checkboxes, this is my approach:
The view
<div class="auto-grid-placement auto-grid-item">
#foreach( $perfumes as $perfume )
#php
$slug = slugafy( $perfume->name );
$checked = ( in_array( $perfume->id, $selectedPerfumes->toArray() )? "checked='checked'" : "")
#endphp
<x-form.label for="{{ $slug }}-{{ $perfume->id }}" class="{{ $disabled }} checkbox-item px-2 py-2 inline-block">
<input wire:click="savePerfumes( {{ $perfume->id }} )" type="checkbox" id="{{ $slug }}-{{ $perfume->id }}" name="selectedPerfumes[]" {{ $checked }} class="" value="{{ $perfume->id }}" {{ $disabled }}> {{ $perfume->name }} - {{ $perfume->id }}
</x-form.label>
#endforeach
#error( "selectedPerfumes" )
<span class="error">{{ $message }}</span>
<!-- /.error -->
#enderror
</div>
The function to save
// Rules
protected $rules = [
"selectedPerfumes" => "array",
"selectedPerfumes.*" => "required|integer"
];
public function savePerfumes( $perfume_id )
{
$this->validate();
if( $this->selectedPerfumes->contains( $perfume_id ))
{
$this->selectedPerfumes = $this->selectedPerfumes->reject( function( $value ) use ($perfume_id) {
return $value == $perfume_id;
});
}else{
$this->selectedPerfumes->push( $perfume_id );
}
if( $this->plant->id != null )
{
$this->plant->perfumes()->sync(
$this->selectedPerfumes
);
}
}
try this
public $selected = [];
protected function rules()
{
return [
...
'selected' => 'required|array',
];
}
public function edit()
{
if ($this->validate()) {
$data = [
'name' => $this->name,
...
];
$plant = Plant::where('id', $this->plant->id)->update($data);
if (!empty($this->selected)) {
$selectedId = Perfume::whereIn('id', $this->selected)->pluck('id');
Plant::findOrFail($this->plant->id)->perfumes()->sync($selectedId);
}
}
}
Related
I am working on this problem and somehow resolved it to a very great extent and almost everything is done. But the Django is rendering my template but not the Context.
I don't know why I have checked it by debugging and my context is rendering but not showing in frontend.
On this template, there is a form with 4 fieldset , I am submitting data in 1st fieldset and the dynamically show o/p accordingly on the second fieldset.
I am attaching screenshot to show what is rendering in template(2nd fieldset)
edit:
I have debugged this and in code all is working fine but it is not showing up in fornt-end, I dont know why
#views.py
def createQuotePage(request):
if request.method == "POST":
# Getting all the value
# saving in Table
saveInUnitsTable(-------some code, removed to shorten question ------)
saveInCustomerTable(-------some code, removed to shorten question ------)
saveInInquiryTable(-------some code, removed to shorten question ------)
flight_suggestions =Flight.objects.filter(sourceairportid=1,destinationairportid=51)
context = {'flight_suggestions':flight_suggestions,"test":"99999999999999999999999999999999999999"}
return render(request,"Freight/create_quote.html",context=context) # <-- here is the PROBLEM
if request.method == "GET":
print("========================GET=======================")
context = {'airport_data' : list(Airport.objects.all()),
'commodity_data':list(Commodity.objects.all()),
'customerType_data':list(Entity.objects.all()),
}
return render(request,"Freight/create_quote.html",context=context)
#scripts.js
(function($) {
"use strict";
$.backstretch;
$('#top-navbar-1').on('shown.bs.collapse', function(){
$.backstretch("resize");
});
$('#top-navbar-1').on('hidden.bs.collapse', function(){
$.backstretch("resize");
});
$('.f1 fieldset:first').fadeIn('slow');
$('.f1 .btn-next').on('click', function() {
//
var parent_fieldset = $(this).parents('fieldset');
var next_step = true;
var current_active_step = $(this).parents('.f1').find('.f1-step.active');
var progress_line = $(this).parents('.f1').find('.f1-progress-line');
//
var formData1 = $("#total-shipment-form").serialize();
var formData2 = $("#units-form").serialize();
var formData3 = $("#customerDetailForm").serialize();
var formData4 = $("#firstFieldset").serialize();
var formData = formData1 + '&' +
formData2 + '&' +
formData3 + '&' +
formData4
$.post("",formData)
.done(function(){
//
console.log('Success : ');
// var parent_fieldset = $(this).parents('fieldset');
// var next_step = true;
// var current_active_step = $(this).parents('.f1').find('.f1-step.active');
// var progress_line = $(this).parents('.f1').find('.f1-progress-line');
if( next_step ) {
parent_fieldset.fadeOut(400, function() {
current_active_step.removeClass('active').addClass('activated').next().addClass('active');
bar_progress(progress_line, 'right');
$(this).next().fadeIn();
scroll_to_class( $('.f1'), 20 );
});
}
//
})
.fail(function(){
console.log('Error : ');
});
});
Edited:-
Html template
<fieldset id="secondFieldset">
<div class="form-group select_all_style">
<input class="form-check-input" type="checkbox" value=""
id="select_all">
<label for="select_all" class="font-bold lh-26 fs-14">Select All</label>
</div>
{{test}}
<div class="airline_wrapper check_box_wrapper">
{{test}}
{% for flight in flight_suggestions %}
<div class="col_2 text-center dhl_text ">
<div class="aviation_wrapper">
<div class="aviation_checkbox">
<input class="form-check-input" type="checkbox" value=""
id="flexCheckDefault">
</div>
<div class="d-inline pl_10">
<!-- <p>Expiry Date <span><b>6 Sep 2022</b></span></p> -->
<h4 class="fw-400 fs-28">{{flight.flightcompany}}</h4>
<p>Air Freight</p>
</div>
</div>
</div>
<div class="col_6">
<div class="flight_container text-center">
<i class="fa-solid fa-plane plane_style"></i>
<div class="flight_details"></div>
<div class="flight_content">
<div>
<h4>{{flight.sourceairportid.airportname}}</h4>
<p>{{flight.sourceairportid.cityid.cityname}}</p>
</div>
<div>
<h4>{{flight.destinationairportid.airportname}}</h4>
<p>{{flight.destinationairportid.cityid.cityname}}</p>
</div>
</div>
<hr>
<div class="d-flex">
<div class="flight_sub_text text-left">
<label for="">Transit Time</label>
<h5>-- Hrs</h5>
<h5>{{flight.trasittime}} Hrs</h5>
</div>
</div>
</div>
</div>
<div class="col_3">
<h4 class="text-center reference_text">Past Reference</h4>
<div class="buy_text_wrapper">
<p>Buy Rate</p>
<p>Sell Rate</p>
</div>
<div class="buy_text_wrapper">
<p>USD 5,500.00</p>
<p>USD 7,000.00</p>
</div>
<h5 class="probabilty_text text-center pt-4"><span><i
class="fa-solid fa-arrow-trend-up"></i> 70%</span>
Winnning Probabilty</h5>
</div>
{% endfor %}
</div>
<div class="f1-buttons">
<button class="btn btn-primary btn-next" type="button">Request Better
Rates</button>
</div>
</fieldset>
In laravel / jquery apps if I need to make checks if user is logged I make in controller:
$loggedUser = Auth::user();
if ( empty($loggedUser->id) ) {
return response()->json(['error_code'=> 1, 'message'=> "You must be logged!"],HTTP_RESPONSE_INTERNAL_SERVER_ERROR);
}
as I do not need to leave the user from the page, but only restrict some functionality
I show error message above using bootstrapGrowl library.
Now with laravel 7 /livewire 1.3 / turbolinks:5 / alpine#v2 I search how can I generate error and
show similar error message, leaving user on the page ?
UPDATED :
Let me explain it with detailed example :
In laravel / jquery apps I have in JS code :
var quiz_quality_radio= $('input[name=quiz_quality_radio]:checked').val()
var href = this_frontend_home_url + "/make-quiz-quality";
$.ajax( {
type: "POST",
dataType: "json",
url: href,
data: {"quiz_quality_id": quiz_quality_radio, "vote_id": this_vote_id, "_token": this_csrf_token},
success: function( response )
{
$('input[name=quiz_quality_radio]:checked').prop('checked', false);
frontendVote.showQuizQualityResults()
popupAlert("Thank you for rating ! Your rate was added!", 'success')
},
error: function( error )
{
$('input[name=quiz_quality_radio]:checked').prop('checked', false);
popupAlert(error.responseJSON.message, 'danger') // 'info', 'success'
}
});
and relative action in control :
public function make_quiz_quality(Request $request)
{
$requestData = $request->all();
$quiz_quality_id = ! empty($requestData['quiz_quality_id']) ? $requestData['quiz_quality_id'] : '';
$vote_id = ! empty($requestData['vote_id']) ? $requestData['vote_id'] : '';
if ( ! Auth::check()) {
return response()->json(['message' => "To rate you must login to the system !"], HTTP_RESPONSE_BAD_REQUEST);
}
if (empty($quiz_quality_id)) {
return response()->json([
'message' => "To rate you must select quiz quality !",
'quiz_quality_id' => $quiz_quality_id
], HTTP_RESPONSE_OK);
}
$vote = Vote::find($vote_id);
if ($vote === null) {
return response()->json([ 'message' => "Vote Item # " . $vote_id . " not found !"],HTTP_RESPONSE_NOT_FOUND);
}
$loggedUser = Auth::user();
$found_count = QuizQualityResult
::getByVoteIdAndUserId($vote_id, $loggedUser->id)
->count();
if ($found_count > 0) {
return response()->json(['message' => "You have already rated '" . $vote->name . "' # vote !", 'vote_id' => $vote_id],
HTTP_RESPONSE_BAD_REQUEST);
}
$newVoteItemUsersResult = new QuizQualityResult();
try {
$newVoteItemUsersResult->quiz_quality_id = $quiz_quality_id;
$newVoteItemUsersResult->vote_id = $vote_id;
$newVoteItemUsersResult->user_id = $loggedUser->id;
DB::beginTransaction();
$newVoteItemUsersResult->save();
DB::commit();
} catch (Exception $e) {
DB::rollBack();
return response()->json(['message' => $e->getMessage(), 'voteCategory' => null], HTTP_RESPONSE_INTERNAL_SERVER_ERROR);
}
return response()->json(['message' => '', 'id' => $newVoteItemUsersResult->id], HTTP_RESPONSE_OK_RESOURCE_CREATED);
} // public function make_quiz_quality(Request $request)
and in case of error generated in error block I show message with function popupAlert
(implemented with bootstrapGrowl), without leaving the page.
That is what I want to make in livewire / turbolinks / alpine app. How can I do it?
UPDATED # 2:
That is just listing of items user can vote for:
<div class="table-responsive">
<table class="table text-primary">
#foreach($quizQualityOptions as $key=>$next_quiz_quality_option)
<tr>
<td>
<input class="" type="radio" name="quiz_quality_radio" id="quiz_quality_radio_{{ $next_quiz_quality_option }}" value="{{ $key }}">
<label class="col-form-label" for="quiz_quality_radio_{{ $next_quiz_quality_option }}">{{ $next_quiz_quality_option }}</label>
</td>
</tr>
#endforeach
</table>
</div>
<div class="row p-3">
<a class="btn btn-primary a_link" onclick="javascript:frontendVote.MakeQuizQuality()">Rate !</a>
</div>
with 2 restrictions :
User must be logged
Any logged user can vote only once
these 2 errors were genarated at server.
UPDATED # 3:
I found decision with using of axios, like :
<button type="submit" class="btn btn-primary btn-sm m-2 ml-4 mr-4 action_link" #click.prevent="submitNewTodo()">
Submit
</button>
submitNewTodo() {
console.log('submitNewTodo::')
let is_insert= 1
let current_toto_id= 1
axios({
method: (is_insert ? 'post' : 'patch'),
url: '/api/todos' + (!is_insert ? "/" + current_toto_id : ''),
data: {
text : this.new_todo_text,
priority : this.new_todo_priority
},
}).then((response) => {
this.new_todo_text= ''
this.new_todo_priority= ''
this.loadTodosRows()
popupAlert( 'Todo ' + (is_insert ? 'added' : 'updated') + ' successfully !', 'success' )
}).catch((error) => {
var validationErrors= convertObjectToArray(error.response.data.errors.text)
this.validation_errors_text= ''
validationErrors.map((next_error, index) => {
if(next_error && typeof next_error[1] != "undefined" ) {
this.validation_errors_text += '<li>'+next_error[1]+'</li>'
}
})
popupErrorMessage(error.response.data.message)
});
},
With it I show message both on success and failure as I need but I see big disadvantage with it
as I use livewire and I would like to use livewire here, if that is possible...
Hope I explained what I want clearly...
Thanks!
With Alpine.js and axios you could do something like this, note that I'm not sure whether or not this_frontend_home_url, this_vote_id and this_csrf_token will be defined.
<div x-data="quiz()">
<div>
<div class="table-responsive">
<table class="table text-primary">
#foreach($quizQualityOptions as $key=>$next_quiz_quality_option)
<tr>
<td>
<input x-model="selected_quiz" class="" type="radio" name="quiz_quality_radio"
id="quiz_quality_radio_{{ $next_quiz_quality_option }}" value="{{ $key }}">
<label class="col-form-label"
for="quiz_quality_radio_{{ $next_quiz_quality_option }}">{{ $next_quiz_quality_option }}</label>
</td>
</tr>
#endforeach
</table>
</div>
<div class="row p-3">
<a class="btn btn-primary a_link" #click="submitQuizQuality()">Rate !</a>
</div>
</div>
</div>
<script>
function quiz() {
return {
selected_quiz: null,
submitQuizQuality() {
const url = this_frontend_home_url + "/make-quiz-quality";
axios.post(url, {
quiz_quality_id: this.selected_quiz,
vote_id: this_vote_id, // no idea where this is coming from,
_token: this_csrf_token // no idea where this is coming from
}).then(() => {
// reset "checked" state
this.selected_quiz = null;
frontendVote.showQuizQualityResults();
popupAlert("Thank you for rating ! Your rate was added!", 'success');
}).catch(error => {
// reset "checked" state
this.selected_quiz = null;
if (error && error.response) {
popupAlert(error.response.message, 'danger')
}
});
}
}
}
</script>
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I am working on an application where I want to implement the django-private-chat in for one to one messaging feature after I did everything which is said in the documentation I ran the server and got to the link http://127.0.0.1:8000/dialogs/ I am getting this error please help me out I have included the error traceback also
dialogs.html:
% extends "base.html" %
{% load static %}
{% load i18n %}
{% block css %}
{{ block.super }}
<link href="{% static "django_private_chat/css/django_private_chat.css" %}" rel="stylesheet" type="text/css" media="all">
{% endblock css %}
{% block content %}
<input id="owner_username" type="hidden" value="{{ request.user.username }}">
<div class="container">
<div class="col-md-3">
<div class="user-list-div">
<ul>
{% for dialog in object_list %}
<li>
{% if dialog.owner == request.user %}
{% with dialog.opponent.username as username %}
<a href="{% url 'dialogs_detail' username %}" id="user-{{ username }}"
class="btn btn-danger">{% trans "Chat with" %} {{ username }}</a>
{% endwith %}
{% else %}
{% with dialog.owner.username as username %}
<a href="{% url 'dialogs_detail' username %}" id="user-{{ username }}"
class="btn btn-danger">{% trans "Chat with" %} {{ username }}</a>
{% endwith %}
{% endif %}
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="col-md-9">
<div class="row">
<div class="col-md-3 col-md-offset-9">
<span class="pull-right" hidden id="typing-text">
<strong>{{ opponent_username }} {% trans "is typing..." %}</strong>
</span>
</div>
<p>
{{ opponent_username }}
</p>
<p class="text-success" id="online-status" style="display: none">{% trans "Online" %}</p>
<p class="text-danger" id="offline-status" style="display: none">{% trans "Offline" %}</p>
<div class="messages-container">
<div id="messages" class="messages">
{% for msg in active_dialog.messages.all %}
<div class="row {% if msg.read %}msg-read{% else %}msg-unread{% endif %}"
data-id="{{ msg.id }}">
<p class="{% if msg.sender == request.user %}pull-left{% else %}pull-right{% endif %}">
<span class="username">{{ msg.sender.username }}:</span>
{{ msg.text }}
<span class="timestamp">– <span
data-livestamp="{{ msg.get_formatted_create_datetime }}">{{ msg.get_formatted_create_datetime }}</span></span>
</p>
</div>
{% endfor %}
</div>
</div>
</div>
<div class="row">
<div class="add-message">
<div class="form-group">
<textarea id="chat-message" class="form-control message"
placeholder="{% trans 'Write a message' %}"></textarea>
</div>
<div class="form-group clearfix">
<input id="btn-send-message" type="submit" class="btn btn-primary pull-right send-message"
style="margin-left: 10px;" value="{% trans 'Send' %}"/>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
{{ block.super }}
<script src="https://cdnjs.cloudflare.com/ajax/libs/scrollmonitor/1.2.0/scrollMonitor.js"
integrity="sha256-BseZlDlA+yL4qu+Voi82iFa5aaifralQEXIjOjaXgeo=" crossorigin="anonymous"></script>
<script>
var base_ws_server_path = "{{ ws_server_path }}";
$(document).ready(function () {
var websocket = null;
var monitor = null;
function initReadMessageHandler(containerMonitor, elem) {
var id = $(elem).data('id');
var elementWatcher = containerMonitor.create(elem);
elementWatcher.enterViewport(function () {
var opponent_username = getOpponnentUsername();
var packet = JSON.stringify({
type: 'read_message',
session_key: '{{ request.session.session_key }}',
username: opponent_username,
message_id: id
});
$(elem).removeClass('msg-unread').addClass('msg-read');
websocket.send(packet);
});
}
function initScrollMonitor() {
var containerElement = $("#messages");
var containerMonitor = scrollMonitor.createContainer(containerElement);
$('.msg-unread').each(function (i, elem) {
if ($(elem).hasClass('opponent')){
initReadMessageHandler(containerMonitor, elem);
}
});
return containerMonitor
}
function getOpponnentUsername() {
return "{{ opponent_username }}";
}
// TODO: Use for adding new dialog
function addNewUser(packet) {
$('#user-list').html('');
packet.value.forEach(function (userInfo) {
if (userInfo.username == getUsername()) return;
var tmpl = Handlebars.compile($('#user-list-item-template').html());
$('#user-list').append(tmpl(userInfo))
});
}
function addNewMessage(packet) {
var msg_class = "";
if (packet['sender_name'] == $("#owner_username").val()) {
msg_class = "pull-left";
} else {
msg_class = "pull-right";
}
var msgElem =
$('<div class="row msg-unread" data-id="' + packet.message_id + '">' +
'<p class="' + msg_class + '">' +
'<span class="username">' + packet['sender_name'] + ': </span>' +
packet['message'] +
' <span class="timestamp">– <span data-livestamp="' + packet['created'] + '"> ' + packet['created'] + '</span></span> ' +
'</p> ' +
'</div>');
$('#messages').append(msgElem);
scrollToLastMessage()
}
function scrollToLastMessage() {
var $msgs = $('#messages');
$msgs.animate({"scrollTop": $msgs.prop('scrollHeight')})
}
function generateMessage(context) {
var tmpl = Handlebars.compile($('#chat-message-template').html());
return tmpl({msg: context})
}
function setUserOnlineOffline(username, online) {
var elem = $("#user-" + username);
if (online) {
elem.attr("class", "btn btn-success");
} else {
elem.attr("class", "btn btn-danger");
}
}
function gone_online() {
$("#offline-status").hide();
$("#online-status").show();
}
function gone_offline() {
$("#online-status").hide();
$("#offline-status").show();
}
function flash_user_button(username) {
var btn = $("#user-" + username);
btn.fadeTo(700, 0.1, function () {
$(this).fadeTo(800, 1.0);
});
}
function setupChatWebSocket() {
var opponent_username = getOpponnentUsername();
websocket = new WebSocket(base_ws_server_path + '{{ request.session.session_key }}/' + opponent_username);
websocket.onopen = function (event) {
var opponent_username = getOpponnentUsername();
var onOnlineCheckPacket = JSON.stringify({
type: "check-online",
session_key: '{{ request.session.session_key }}',
username: opponent_username
{# Sending username because the user needs to know if his opponent is online #}
});
var onConnectPacket = JSON.stringify({
type: "online",
session_key: '{{ request.session.session_key }}'
});
console.log('connected, sending:', onConnectPacket);
websocket.send(onConnectPacket);
console.log('checking online opponents with:', onOnlineCheckPacket);
websocket.send(onOnlineCheckPacket);
monitor = initScrollMonitor();
};
window.onbeforeunload = function () {
var onClosePacket = JSON.stringify({
type: "offline",
session_key: '{{ request.session.session_key }}',
username: opponent_username,
{# Sending username because to let opponnent know that the user went offline #}
});
console.log('unloading, sending:', onClosePacket);
websocket.send(onClosePacket);
websocket.close();
};
websocket.onmessage = function (event) {
var packet;
try {
packet = JSON.parse(event.data);
console.log(packet)
} catch (e) {
console.log(e);
}
switch (packet.type) {
case "new-dialog":
// TODO: add new dialog to dialog_list
break;
case "user-not-found":
// TODO: dispay some kind of an error that the user is not found
break;
case "gone-online":
if (packet.usernames.indexOf(opponent_username) != -1) {
gone_online();
} else {
gone_offline();
}
for (var i = 0; i < packet.usernames.length; ++i) {
setUserOnlineOffline(packet.usernames[i], true);
}
break;
case "gone-offline":
if (packet.username == opponent_username) {
gone_offline();
}
setUserOnlineOffline(packet.username, false);
break;
case "new-message":
if (packet['sender_name'] == opponent_username || packet['sender_name'] == $("#owner_username").val()) {
addNewMessage(packet);
if (packet['sender_name'] == opponent_username) {
initReadMessageHandler(monitor, $("div[data-id='" + packet['message_id'] + "']"));
}
} else {
flash_user_button(packet['sender_name']);
}
break;
case "opponent-typing":
var typing_elem = $('#typing-text');
if (!typing_elem.is(":visible")) {
typing_elem.fadeIn(500);
} else {
typing_elem.stop(true);
typing_elem.fadeIn(0);
}
typing_elem.fadeOut(3000);
break;
case "opponent-read-message":
if (packet['username'] == opponent_username) {
$("div[data-id='" + packet['message_id'] + "']").removeClass('msg-unread').addClass('msg-read');
}
break;
default:
console.log('error: ', event)
}
}
}
function sendMessage(message) {
var opponent_username = getOpponnentUsername();
var newMessagePacket = JSON.stringify({
type: 'new-message',
session_key: '{{ request.session.session_key }}',
username: opponent_username,
message: message
});
websocket.send(newMessagePacket)
}
$('#chat-message').keypress(function (e) {
if (e.which == 13 && this.value) {
sendMessage(this.value);
this.value = "";
return false
} else {
var opponent_username = getOpponnentUsername();
var packet = JSON.stringify({
type: 'is-typing',
session_key: '{{ request.session.session_key }}',
username: opponent_username,
typing: true
});
websocket.send(packet);
}
});
$('#btn-send-message').click(function (e) {
var $chatInput = $('#chat-message');
var msg = $chatInput.val();
if (!msg) return;
sendMessage($chatInput.val());
$chatInput.val('')
});
setupChatWebSocket();
scrollToLastMessage();
});
</script>
{% endblock %}
base.html:
{% load static %}
<!-- Their site uses old school block layout -->
{% block extra_js %}
<!-- Your package using 2SoD block layout -->
{% block javascript %}
<script src="{% static 'js/ninja.js' %}" type="text/javascript"></script>
{% endblock javascript %}
{% endblock extra_js %}
It seems you are calling {{ block.super }} on a base template.
You should include a base template using {% extends "base_template_name.html" %} before calling {{ block.super }}.
This would include content from the super template ("base_template_name.html") in your "dialog.html" template, instead of overriding it. You may also try just removing or commenting out the {{ block.super }} call if you don't need any content from the super template.
Please post your code here if you still can't get it to work. Hope it works for you!
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% block css %}
<link href="{% static "django_private_chat/css/django_private_chat.css" %}" rel="stylesheet" type="text/css" media="all">
{% endblock css %}
I would like to add an Image as background by selecting from a module. The new extension is created under starter_module name.
Please, do not suggest to add image in css file.
The image set in module is not saving, this would be the issue, if you know the solution, please add in your comment.
Many thanks,
I added in: admin/view/template/extension/module/starter_module.twig
<div class="form-group">
<label class="col-sm-2 control-label" for="input-headbg">Header Image</label>
<div class="col-sm-10">
<a href="" id="thumb-headbg" data-toggle="image" class="img-thumbnail">
<img src="{{ headbg }}" alt="" title="" data-placeholder="{{ placeholder }}" />
</a>
<input type="hidden" name="config_headbg" value="{{ config_headbg }}" id="input-headbg" />
</div>
</div>
In admin/controller/extension/module/starter_module.php
//Top page
// Module Image
$this->model_setting_setting->editSetting('config_headbg', $this->request->post);
// Module Image
// Module Image
if (isset($this->request->post['config_headbg'])) {
$data['headbg'] = $this->request->post['config_headbg'];
} else {
$data['headbg'] = $this->config->get('config_headbg');
}
$this->load->model('tool/image');
if (isset($this->request->post['config_headbg']) && is_file(DIR_IMAGE . $this->request->post['config_headbg'])) {
$data['headbg'] = $this->model_tool_image->resize($this->request->post['config_headbg'], 100, 100);
} elseif ($this->config->get('config_headbg') && is_file(DIR_IMAGE . $this->config->get('config_headbg'))) {
$data['headbg'] = $this->model_tool_image->resize($this->config->get('config_headbg'), 100, 100);
} else {
$data['headbg'] = $this->model_tool_image->resize('no_image.png', 100, 100);
}
$data['placeholder'] = $this->model_tool_image->resize('no_image.png', 100, 100);
// Module Image
In catalog/controller/common/header.php
if (is_file(DIR_IMAGE . $this->config->get('config_headbg'))) {
$data['headbg'] = $server . 'image/' . $this->config->get('config_headbg');
} else {
$data['headbg'] = '';
}
In catalog/view/theme/default/template/common/header.twig
{{ headbg }}
Many thanks,
The files you check here https://github.com/bblori/OpenCart3-Module-Header-Image
I'm new to opencart but from what I see in your form the input is named headbg
<input type="hidden" name="headbg" value="{{ config_headbg }}" id="input-headbg" /> and in admin controller you check for config_headbg if (isset($this->request->post['config_headbg']))
hope all is well. I am trying to install Opencart (2.0.3) into a subdirectory (Ie. www.website.com/shop/) I want the root URL www.website.com to go to a Login page, where once a user logs in. It will redirect them to the /shop/ portion of the site and allow them to continue their business. I was wondering what the easiest way was to accomplish this. Would I install everything in the root folder, and then modify the .htaccess file along with the config files? Then how would i Make the login files work in the root folder? I tried installing everything first into the subdirectory /shop/... but then I get issues trying to figure out how to get files in the root folder to work.
Thanks in advance!
Yes, need to work with ajax functionality as below. In the index.php insert the following code and replace URL_WITH_SHOP with your urlshop. Then I have taken "shop" as sub-folder installation if it is different then replace "shop" with your sub-folder name:
<script src="shop/catalog/view/javascript/jquery/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="shop/catalog/view/javascript/bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<div class="container">
<div class="row">
<div id="content" class="col-sm-12 ">
<div class="row ">
<div class="col-sm-6" style="margin: 0px auto; float: none;">
<div class="well">
<h2>Returning Customer</h2>
<p><strong>I am a returning customer</strong></p>
<form method="post" enctype="multipart/form-data">
<div class="error"></div>
<div class="form-group">
<label class="control-label" for="input-email">E-Mail Address</label>
<input type="text" name="email" value="" placeholder="E-Mail Address" id="input-email" class="form-control" />
</div>
<div class="form-group">
<label class="control-label" for="input-password">Password</label>
<input type="password" name="password" value="" placeholder="Password" id="input-password" class="form-control" />
</div>
<button type="button" id="button-cart" data-loading-text="Checking login" class="btn btn-primary ">Login</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript"><!--
$('#button-cart').on('click', function() {
$.ajax({
url: 'shop/index.php?route=account/loginajax',
type: 'post',
data: $('input[type=\'text\'], input[type=\'password\']'),
dataType: 'json',
beforeSend: function() {
$('#button-cart').button('loading');
},
complete: function() {
$('#button-cart').button('reset');
},
success: function(json) {
$('.alert, .text-danger').remove();
$('.form-group').removeClass('has-error');
if (json['error']) {
$('.error').after('<div class="alert alert-danger has-error">' + json['error'] + '</div>');
}
if (json['success']) {
$('.error').after('<div class="alert alert-success">' + json['success'] + '</div>');
window.location = "URL_WITH_SHOP";
}
}
});
});
//--></script>
Above is the presentation layer, now let's make the logical layer, go to shop/catalog/controller/account and create loginajax.php and paste following code:
<?php
class ControllerAccountLoginAjax extends Controller
{
private $error = array();
public function index()
{
$this->load->model('account/customer');
$json = array();
// Login override for admin users
if (!empty($this->request->get['token'])) {
$this->event->trigger('pre.customer.login');
$this->customer->logout();
$this->cart->clear();
unset($this->session->data['wishlist']);
unset($this->session->data['payment_address']);
unset($this->session->data['payment_method']);
unset($this->session->data['payment_methods']);
unset($this->session->data['shipping_address']);
unset($this->session->data['shipping_method']);
unset($this->session->data['shipping_methods']);
unset($this->session->data['comment']);
unset($this->session->data['order_id']);
unset($this->session->data['coupon']);
unset($this->session->data['reward']);
unset($this->session->data['voucher']);
unset($this->session->data['vouchers']);
$customer_info = $this->model_account_customer->getCustomerByToken($this->request->get['token']);
if ($customer_info && $this->customer->login($customer_info['email'], '', true)) {
// Default Addresses
$this->load->model('account/address');
if ($this->config->get('config_tax_customer') == 'payment') {
$this->session->data['payment_address'] = $this->model_account_address->getAddress($this->customer->getAddressId());
}
if ($this->config->get('config_tax_customer') == 'shipping') {
$this->session->data['shipping_address'] = $this->model_account_address->getAddress($this->customer->getAddressId());
}
$this->event->trigger('post.customer.login');
$this->response->redirect($this->url->link('account/account', '', 'SSL'));
}
}
if ($this->customer->isLogged()) {
$this->response->redirect($this->url->link('account/account', '', 'SSL'));
}
if (!$json) {
$this->load->language('account/login');
$this->document->setTitle($this->language->get('heading_title'));
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
$json['success'] = "Successfully logging in! ";
unset($this->session->data['guest']);
// Default Shipping Address
$this->load->model('account/address');
if ($this->config->get('config_tax_customer') == 'payment') {
$this->session->data['payment_address'] = $this->model_account_address->getAddress($this->customer->getAddressId());
}
if ($this->config->get('config_tax_customer') == 'shipping') {
$this->session->data['shipping_address'] = $this->model_account_address->getAddress($this->customer->getAddressId());
}
// Add to activity log
$this->load->model('account/activity');
$activity_data = array(
'customer_id' => $this->customer->getId(),
'name' => $this->customer->getFirstName() . ' ' . $this->customer->getLastName()
);
$this->model_account_activity->addActivity('login', $activity_data);
}
else{
$json['error'] = $this->language->get('error_login');
}
$data['breadcrumbs'] = array();
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_home'),
'href' => $this->url->link('common/home')
);
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_account'),
'href' => $this->url->link('account/account', '', 'SSL')
);
$data['breadcrumbs'][] = array(
'text' => $this->language->get('text_login'),
'href' => $this->url->link('account/login', '', 'SSL')
);
$data['heading_title'] = $this->language->get('heading_title');
$data['text_new_customer'] = $this->language->get('text_new_customer');
$data['text_register'] = $this->language->get('text_register');
$data['text_register_account'] = $this->language->get('text_register_account');
$data['text_returning_customer'] = $this->language->get('text_returning_customer');
$data['text_i_am_returning_customer'] = $this->language->get('text_i_am_returning_customer');
$data['text_forgotten'] = $this->language->get('text_forgotten');
$data['entry_email'] = $this->language->get('entry_email');
$data['entry_password'] = $this->language->get('entry_password');
$data['button_continue'] = $this->language->get('button_continue');
$data['button_login'] = $this->language->get('button_login');
if (isset($this->error['warning'])) {
$data['error_warning'] = $this->error['warning'];
} else {
$data['error_warning'] = '';
}
$data['action'] = $this->url->link('account/login', '', 'SSL');
$data['register'] = $this->url->link('account/register', '', 'SSL');
$data['forgotten'] = $this->url->link('account/forgotten', '', 'SSL');
if (isset($this->session->data['success'])) {
$data['success'] = $this->session->data['success'];
unset($this->session->data['success']);
} else {
$data['success'] = '';
}
if (isset($this->request->post['email'])) {
$data['email'] = $this->request->post['email'];
} else {
$data['email'] = '';
}
if (isset($this->request->post['password'])) {
$data['password'] = $this->request->post['password'];
} else {
$data['password'] = '';
}
} else {
$json['error'] = $this->language->get('error_login');
}
$this->response->addHeader('Content-Type: application/json');
$this->response->setOutput(json_encode($json));
}
protected function validate() {
$this->event->trigger('pre.customer.login');
// Check how many login attempts have been made.
$login_info = $this->model_account_customer->getLoginAttempts($this->request->post['email']);
if ($login_info && ($login_info['total'] >= $this->config->get('config_login_attempts')) && strtotime('-1 hour') < strtotime($login_info['date_modified'])) {
$this->error['warning'] = $this->language->get('error_attempts');
}
// Check if customer has been approved.
$customer_info = $this->model_account_customer->getCustomerByEmail($this->request->post['email']);
if ($customer_info && !$customer_info['approved']) {
$this->error['warning'] = $this->language->get('error_approved');
}
if (!$this->error) {
if (!$this->customer->login($this->request->post['email'], $this->request->post['password'])) {
$this->error['warning'] = $this->language->get('error_login');
$this->model_account_customer->addLoginAttempt($this->request->post['email']);
} else {
$this->model_account_customer->deleteLoginAttempts($this->request->post['email']);
$this->event->trigger('post.customer.login');
}
}
return !$this->error;
}
}
This will help you.
Download files and folders for above codes
Hope it also help you
If you just want the login page then here is the tricks, create index.php or index.html at root folder then paste the following code and change URL_WITH_SHOP in the code with your url with shop like "http://www.example.com/shop" :
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<div class="container">
<div class="row">
<div id="content" class="col-sm-12 ">
<div class="row ">
<div class="col-sm-6" style="margin: 0px auto; float: none;">
<div class="well">
<h2>Returning Customer</h2>
<p><strong>I am a returning customer</strong></p>
<form action="URL_WITH_SHOP/index.php?route=account/login" method="post" enctype="multipart/form-data">
<div class="form-group">
<label class="control-label" for="input-email">E-Mail Address</label>
<input type="text" name="email" value="" placeholder="E-Mail Address" id="input-email" class="form-control" />
</div>
<div class="form-group">
<label class="control-label" for="input-password">Password</label>
<input type="password" name="password" value="" placeholder="Password" id="input-password" class="form-control" />
</div>
<input type="submit" value="Login" class="btn btn-primary" />
</form>
</div>
</div>
</div>
</div>
</div>
</div>
The issue will be if the customer enters wrong username and password then it redirects to the actual login page.