3

Mediante una solución de @amenadiel donde mediante datos de PHP JSON se genera varias lista de preguntas, se puede observar la demostración en linea.

<?php
    session_start();
    $conn = mysqli_connect("localhost","root","","1_examen") or die("Connection failed".mysqli_connect_error());

    $preguntas=[];
    $sql = "SELECT * FROM Question";
    $result = $conn->query($sql);

    while($row = mysqli_fetch_assoc($result)) {
        $preguntas[] = [
            'name' => 'respuesta_'.$row["Id"],
            'pregunta' => $row["Question"],
            'alternativas' => [$row["A1"], $row["A2"],$row["A3"],$row["A4"]],
            'respuesta' => null
        ];
    }
?>
<!DOCTYPE html>
<html>
<head>
    <title></title>
    <link rel="stylesheet" type="text/css" href="assets/css/style.css">
    <script src="https://a...content-available-to-author-only...s.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<!--
    <input type="radio" name="q" id="q" value="Barry Sanders">
-->
<body>
    <script type="text/javascript">
        var preguntas = <?php echo json_encode($preguntas); ?>;
        var pregunta_actual = 0;
    </script>
    <script type="text/javascript" src="assets/js/question.js"></script>
    <script type="text/javascript">
        $(function() {
            $('#enviar').on('click', function() {
                $('#formulario').submit();
            });
        });
    </script>

    <div id="container">
        <div class="controles">
            <a id="retroceder"> < retroceder </a>
            <a id="avanzar"> avanzar > </a>
            <a id="enviar"> enviar respuestas </a>
        </div>
        <hr>
        <div class="container1">
            <div id="tiempo_restante"></div>
            <ul id="preguntas">
                <!-- -->
            </ul>
        </div>
        <!--<div class="respuestas"></div>-->
        <form id="formulario" name="form" class="respuestas" method="POST" action="result.php">
            <!---->
        </form>
    </div>
</body>
</html>

Cada respuesta seleccionada de cada pregunta se va guardando los datos de esta forma:

<input type="radio" name="q" id="q" value="Barry Sanders">

Pruebas realizadas mediante los comentarios de @A.Cedano

Estoy usando este código ajax que me han enviado por mensaje, me familiarizo con este código ajax, lo entiendo muy bien su funcionamiento.

$(function() {
    var frm = $('#formulario');
    frm.submit(function(e){
        e.preventDefault();
        var formData = frm.serialize();
        formData += '&' + $('#enviar').attr('name') + '=' + $('#enviar').attr('value');
        var url = "result.php";
        $.ajax({
            type: frm.attr('method'),
            url: url,
            data: formData,
        })
        .done(function(data) {
            let res = JSON.parse(data);
            // si es true el estado
            if(res.status){
                $('.success').fadeIn();
                $('.success').html(res.message).delay(3000).fadeOut(3000);
                $(frm)[0].reset();
                $(frm).hide();
            } else {
                // si es false el estado
                //mensaje de error...
            }
        })
        .fail(function() {
            $('.fail').fadeIn();
            $('.fail').html(textStatus).delay(3000).fadeOut(3000);
        })
    });
});

El formulario sigue estando igual el único cambio que hice fue eliminar el action quedando de esta forma:

<form id="formulario" name="form" class="respuestas" method="POST">

En el archivo result.php borre todo, para ver si funcionaba el envió al igual cuando se termina el tiempo.

Dejando solamente esto:

<?php
    echo json_encode(['status'=> true, 'message'=>"Evaluación recibida"]);
?>

Efectivamente el mensaje se muestra en <div class="success"></div> tanto al terminar el tiempo permitido de la evaluación, de la misma forma al enviar respuesta -> <a id="enviar"> enviar respuestas </a>.

El código encargado para evaluar los resultados de la evaluación es el siguiente:

result.php

<?php
    session_start();
    $conn = mysqli_connect("localhost","root","admin","Examination") or die("Connection failed".mysqli_connect_error());
        date_default_timezone_set("Asia/Kolkata");
        $score = 0;
    $results = $_SESSION["result"];
    $name = $_SESSION["name"];
    $answers = array();
    setcookie("clock", "", time() - 3600);
    for($i=0;$i<sizeof($results);$i++)
    {
        if($results[$i] == 1)
            $score++;
    }
            $t=0;
    $sql = "SELECT * FROM question";
        $result = $conn->query($sql);
        while($row = mysqli_fetch_assoc($result)){
        $answers[$t] = $row["Answer"];
        $t++;
    }

    $sql = "INSERT INTO user(Name,Score) values('$name',$score)";
    $conn->query($sql);

?>
            <table border="1px" id="table">
                <tr><th>Question</th><th>Your Answer</th><th>Correct Answer</th><th>Points Scored</th></tr>
                <?php
                for($i=0;$i<10;$i++)
                    {
                        $temp = $i+1;
                        if($results[$i] == 0)
                        echo "<tr style='background-color: #FADBD8  ;'>";
                        else
                        echo "<tr style='background-color: #D5F5E3  ;'>";
                        echo "<td>".$temp."</td><td>".$_SESSION["answer"][$i]."</td><td>".$answers[$i]."</td><td>".$results[$i]."</td></tr>";
                    }
                ?>
            </table>

Generaba y mostraba de esta manera los resultados:

introducir la descripción de la imagen aquí

Mi problema es que no entiendo como mostrar los resultados de la evaluación y el segundo problema es, como puedo ocultar el proceso anterior es decir ocultar la evaluación al enviar las respuesta/terminar el tiempo permitido de la evaluación.

Quizás por el mismo ajax se pueda ocular esa información mediante:

            if(res.status){
                $('.success').fadeIn();
                $('.success').html(res.message).delay(3000).fadeOut(3000);
                $(frm)[0].reset();
                $(frm).hide();
            }

Pero aprovechando que la evaluación es en la misma página como puedo hacer uso del mismo diseño de la evaluación para así mostrar los resultados correctos de color verde y las respuestas incorrectas de color rojo.

Por ejemplo:

introducir la descripción de la imagen aquí

Jacks
  • 173
  • 1
  • 10
  • ¿Dónde envías los datos al archivo `result.php`? Deberías enviar una petición vía Ajax que haga referencia a tu archivo PHP, enviándole también los datos. Eso falta en tu código. – A. Cedano Oct 18 '18 at 10:11
  • Hola @A.Cedano no entiendo, seguí todos los pasos del [Bonus Track](https://es.stackoverflow.com/questions/199567/c%C3%B3mo-generar-un-listados-de-botones-de-las-preguntas-existentes-de-manera-din%C3%A1m) para implementar el `front` de `PHP` en la explicación me indica que la guía resolvería lo que falta :( – Jacks Oct 18 '18 at 13:15
  • En tu código hay dos formularios, el que tiene como `action` al archivo `result.php` aparece sin nada, y hay otro que no tiene atributo `action`. Si quieres enviar datos al servidor para ser procesados y permanecer en la misma página, como dices en el título de la pregunta, debes enviarlo por Ajax, indicando en la petición Ajax qué archivo PHP se encargará de recibir/procesar los datos. La finalidad de Ajax es precisamente establecer comunicación cliente/servidor desde una misma página, sin necesidad de recargarla. Sólo que hay de fondo otro archivo (`result.php`) que recibe/procesa los datos – A. Cedano Oct 18 '18 at 13:24
  • @A.Cedano Sí exactamente el archivo `result.php` es que procesa la calificación de la evaluación, en la forma de enviar al archivo `result.php` no funciona, entonces la mejor idea y sobre todo para un diseño más agradable es que los resultados se muestren en la misma página , pero no logro entender como debo hacerlo, mediante `ajax` solo he aprendido insertar datos y mostrar mensajes personalizados como validar formulario y mostrar mensajes de éxitos, pero ya generar todo lo que hace el `result.php` mediante `ajax` me pierdo. – Jacks Oct 18 '18 at 13:34
  • Ajax funciona igual sin importar lo que haga `result.php`. Por ejemplo, Ajax tiene una función `done` que recibe la respuesta que le enviará `result.php`. Esa respuesta puede ser un JSON, puede ser un simple texto como `echo "Todo OK";` o puede ser un XML o lo que sea. Simplemente tienes que poner en el `dataType` de Ajax el tipo de respuesta que devolverá el servidor y leerla desde el `done`. Supongamos que es un JSON. Lo lees en el `done` construyes digamos una tabla, o un mensaje y luego lo muestras en un contenedor (un `div` por ejemplo) que exista en la página donde está el formulario... – A. Cedano Oct 18 '18 at 13:38
  • @A.Cedano Voy a indagar en la web, no he usado `done` – Jacks Oct 18 '18 at 13:43
  • [Mira aquí un ejemplo muy sencillo de cómo funciona Ajax](https://es.stackoverflow.com/a/203091/29967). Hace una llamada a la API de Github, la cual responde con un archivo JSON (imaginemos que tu archivo `results.php` devuelve un JSON parecido). En el `done` se desglosa ese JSON y se crean botones para cada usuario (esto se hace porque era el requerimiento en esa pregunta... en vez de botones se puede generar otra cosa, como un texto, llenar unos `input` , etc.). El contenido generado es finalmente agregado a un contenedor que se encuentra en la misma página sin tener que recargarla. – A. Cedano Oct 18 '18 at 13:52
  • Hola @A.Cedano he logrado obtener respuesta, pero no entiendo como mostrar los resultados de la evaluación y ocultar contenidos en la misma página ya que al evaluarse en la misma página deben ocultarse ciertos contenidos. – Jacks Oct 27 '18 at 23:21
  • El problema principal de tu código se llama **incoherencia**. En el `done` tu intentas esto: `let res = JSON.parse(data);` lo cual quiere decir que la petición espera un JSON como respuesta del servidor, pero en `result.php` **no eres coherente**, porque imprimes cualquier cosa menos un JSON. En este tipo de peticiones debes hacer un control estricto del código en el servidor de forma que **por pantalla no salga nada más que un JSON**. Incluso la tabla que construyes en el PHP deberías construirla en el cliente (así descargas de trabajo al servidor, delegando en el cliente)... – A. Cedano Oct 28 '18 at 00:43
  • ... **coherencia** en el código es algo que debes observar en las peticiones Ajax, de lo contrario no estarás aprovechando sus posibilidades y no te va a funcionar. El **principio a seguir** en tu caso es muy simple: *mandas a pedir datos al servidor, indicándole que los quieres en un formato dado (JSON), recibes los datos en el cliente, los lees y los presentas en el cliente como quieras: una tabla, un form, un div, etc*. Si observas, en la prueba simple que hiciste funcionaba, porque ese principio era respetado. Si entiendes eso y lo aplicas al pie de la letra, lo demás es pan comido... – A. Cedano Oct 28 '18 at 00:47
  • ... siguiendo ese principio, tu código PHP debe evitar por ejemplo esto: `die("Connection failed".mysqli_connect_error());` y debe evitar toda la lectura que haces dentro de él. **Debe recoger los datos en un arreglo** y devolverlos al cliente como un JSON usando `json_encode`. Le puedes poner un `header` adecuado y así no necesitarás usar `JSON.parse` en el cliente. Lamentablemente ahora no tengo tiempo para escribirte una respuesta aplicando todo lo dicho, pero yo y otros hemos hablado... [Por ejemplo aquí (ver 4)](https://es.stackoverflow.com/a/128139/29967) se aplica código **coherente**. – A. Cedano Oct 28 '18 at 00:50
  • @A.Cedano pasa que yo le dejé una respuesta propuesta que menciona un `result.php` pero no es realmente detallado. Lo mismo en la manera de obtener las preguntas. Mi intención era que el usuario tomara eso para desarrollar su solución. En la respuesta a esta pregunta fui más allá e implementé el backend (sin BBDD, sólo un array en duro). Evidentemente si mi solución era con un `
    ` nunca iba a llegar a la solución ajax.
    – ffflabs Oct 30 '18 at 10:30
  • @amenadiel por varias decenas de preguntas que he visto parecidas a esta, en las que casi todas el problema es la **coherencia** en el código, intuyo que los programadores que vienen por aquí ignoran ese principio muy básico. Algunas veces he pensado algo así como una pregunta que se Wiki de comunidad que explique de una forma detallada y simple algunos principios fundamentales de Ajax que veo son ignorados frecuentemente, como el hecho de que si la petición espera un JSON no puedes escribir un código en el servidor que saque por pantalla lo que le parezca. – A. Cedano Oct 30 '18 at 10:46
  • @A.Cedano no es mala idea, aunque yo conozco gente que se gana la vida en esto y todavía usa ajax para traerse HTML – ffflabs Oct 31 '18 at 00:29

3 Answers3

2

Basándome en tu pregunta anterior, tomé las mismas preguntas de mi respuesta:

En un PHP escribí un array en duro (que tú debes obtener de una query)

<?php

$respuestas = [
    [
        'name'         => 'respuesta_1',
        'pregunta'     => 'Cuanto es 2+2?',
        'alternativas' => [1, 2, 3, 4],
        'respuesta'    => 4,
    ],
    [
        'name'         => 'respuesta_2',
        'pregunta'     => 'Vive en una Piña debajo del mar',
        'alternativas' => ['Bob Esponja', 'Patricio Estrella', 'Calamardo', 'Aquaman'],
        'respuesta'    => 'Bob Esponja',
    ],
    [
        'name'         => 'respuesta_3',
        'pregunta'     => 'Cuanto es 3 x 6 ?',
        'alternativas' => [18, 36, '3x6', 4],
        'respuesta'    => 18,
    ],
    [
        'name'         => 'respuesta_4',
        'pregunta'     => 'Mejor sitio web de preguntas y respuestas?',
        'alternativas' => ['stackoverflow español', 'quora', 'answers.org', 'gmail'],
        'respuesta'    => 'stackoverflow español',
    ],
    [
        'name'         => 'respuesta_5',
        'pregunta'     => 'Cuanto es 3+3?',
        'alternativas' => [3, 12, 6, 33],
        'respuesta'    => 6,
    ],
    [
        'name'         => 'respuesta_6',
        'pregunta'     => 'Capital de USA?',
        'alternativas' => ['New York', 'Washington', 'Metropolis', 'Ciudad Gótica'],
        'respuesta'    => 'Washington',
    ],
];


$preguntas = [];

foreach($respuestas as $index => $respuesta) {
    $preguntas[]=$respuesta;
    $preguntas[$index]['respuesta']=null;
}

El array de respuestas contiene la alternativa correcta, así que creas un array de preguntas que elimina ese campo (lo deja en null).

En el landing de la prueba dibujas el contenido del array de preguntas. El formulario se envía a otro landing donde se comparan las respuestas con la alternativa correcta.

https://examples.ffflabs.com/prueba.php

Te dejé un gist con el código: https://gist.github.com/amenadiel/0e1193c36c1eaaa238955cf1e2e633c7

Para hacerlo sin recargar la página

Es casi lo mismo, sólo que el script que evalúa ya no escribe HTML sino el json del resultado. El mismo landing de las preguntas parsea ese resultado e inyecta dinámicamente el HTML a una tabla.

https://examples.ffflabs.com/prueba_ajax.php

https://gist.github.com/amenadiel/5624a99ebcd739542d5cc35b0f32a3b3

Para desplegar los resultados usando la misma botonera de las preguntas no es difícil pero implica replicar el flujo inicial redibujando las cajitas y el contenido del div derecho. Pienso que hay bastante en la respuesta como para que puedas hacerlo tú mismo.

Bonus Track:

Si quieres añadir letras ( A), B), C), etc) a las opciones

Puedes declarar un arreglo de letras:

 var  letras = ['A','B','C','D','E','F'];

Al insertar las opciones:

elemento.alternativas.forEach((alternativa,index) => {
    var letra=letras[index],
        option = jQuery(`
        <label>
            <input type="radio" name="${elemento.name}" value="${alternativa}" >
               ${letra}) ${alternativa}
        <label>`);
    respuesta.append(option);
});

Puedes jugar con los estilos del label para que no se muestra el radio, y darle un color distinto a la letra para que denote que es un elemento de lista. Total, pinchar el label equivale a pinchar el input, así que todo lo que hagas con estilos es inofensivo.

ffflabs
  • 21,223
  • 25
  • 48
  • Gracias, si es suficiente` perdona si cauce molestia :(, amigo disculpa una sola pregunta en cada input radio como le agregaría un nombre, por ejemplo tomando una de las preguntas, cuanto es 2+2? `A) 1` `B ) 2` `C) 3` `D) 4` – Jacks Oct 28 '18 at 21:07
0

El campo $_POST["submit"] no está definido en la forma (al menos en el código que has compartido), dado que no existe ningún elemento con ese nombre. Esto ocurre dado que no estás enviando la información haciendo uso de un botón <input type="submit" name="submit" /> que es lo más común en el posteo de una forma.

Un pequeño workaround sería modificar el código de tu forma #formulario de la siguiente manera:

<form id="formulario" name="form" class="respuestas" method="POST" action="result.php">
    <input type="hidden" name="submit" />
    <!---->
</form>
Niche
  • 1,364
  • 4
  • 15
  • Hola @Niche tengo el código `javascript` que envía el formulario `$(function() { $('#enviar').on('click', function() { $('#formulario').submit(); }); });` si agrego ese campo `input` oculto no envía lo datos, es como se se trancara. – Jacks Oct 27 '18 at 21:39
-1

¿Verificaste primero que la consulta que necesitas esta correcta? También con script y un alert(); dentro de la consulta puedes verificar si entra o no a la consulta como tal.

<?php
session_start();
$conn = mysqli_connect("localhost","root","admin","Examination") or die("Connection failed".mysqli_connect_error());
    date_default_timezone_set("Asia/Kolkata");
    $score = 0;
$results = $_SESSION["result"];
$name = $_SESSION["name"];
$answers = array();
setcookie("clock", "", time() - 3600);
for($i=0;$i<sizeof($results);$i++)
{
    if($results[$i] == 1)
        $score++;
}
        $t=0;
$sql = "SELECT * FROM question";
    $result = $conn->query($sql);
    while($row = mysqli_fetch_assoc($result)){
    $answers[$t] = $row["Answer"];
    $t++;
}
if(isset($_POST["submit"])){
   echo "<script>alert('Ingreso a mi consulta');</script>"
    $sql = "INSERT INTO user(Name,Score) values('$name',$score)";
    $conn->query($sql);
    header('Location:MainPage.php');
}
?>
Niche
  • 1,364
  • 4
  • 15